2011-06-08 10 views
17

मेरे पास एक चेक अपवाद को लपेटने के सही तरीके के बारे में काफी विस्तृत प्रश्न है, और जिस तरह से गुवा इसे करता है। (लंबाई के लिए क्षमा चाहते हैं लेकिन मैं अपने विचार प्रक्रिया नीचे प्राप्त करना चाहते हैं)जावा: चेक अपवादों को लपेटने की मानक विधि


मानक Runnable इंटरफ़ेस इस तरह दिखता है:

public interface Runnable 
{ 
    public void run(); 
} 

जहां run() एक जाँच अपवाद नहीं फेंक सकते हैं।

तो अगर मैं जो कार्यों के लिए जो अपवाद जाँच फेंक रैप करने के लिए प्रयोग किया जाता है एक Runnable करना चाहते हैं, और मैं बात उन अपवादों, बल्कि Runnable.run() में खुद से संभाल Runnable.run() कॉल करने के लिए करना चाहते हैं, मैं में अपवाद रैप करने के लिए है एक अनचेक अपवाद।

तो थोड़ी देर के लिए मैं उपयोग कर रहा था:

Runnable r = new Runnable { 
    @Override public void run() 
    { 
     try { 
      doNastyStuff(); 
     } 
     catch (NastyException e) 
     { 
      throw new RuntimeException(e); 
     } 
    }  
}; 

और उसके बाद मैं एक ऊपरी स्तर में RuntimeException संभाल कर सकते हैं। तो सिवाय मैं लगा, कि क्या मैं वास्तव में चाहते हैं अलग से एक लिपटे अपवाद को संभालने के लिए, के बाद से मैं जानता हूँ कि इसके सिमेंटिक एक जाँच अपवाद रैप करने के लिए हो रहा है, इसलिए मैं इस सहायक वर्ग ने लिखा है:

/** 
* Wrapped exception: the purpose of this is just to wrap another exception, 
* and indicate that it is a wrapped exception 
*/ 
public class WrappedException extends RuntimeException 
{ 
    /** 
    * @param t any throwable 
    */ 
    public WrappedException(Throwable t) 
    { 
     super(t); 
    } 
} 

और फिर मैं यह कर सकता :

/* place that produces the exception */ 
... 
catch (NastyException e) 
{ 
    throw new WrappedException(e); 
} 

... 
/* upper level code that calls Runnable.run() */ 
try 
{ 
    ... 
    SomeOtherNastyCode(); 
    r.run(); 
    ... 
} 
catch (SomeOtherNastyException e) 
{ 
    logError(e); 
} 
catch (WrappedException e) 
{ 
    logError(e.getCause()); 
} 

और ऐसा लगता है कि यह बहुत अच्छा काम करता है।

लेकिन अब मैं सोच रहा हूं, ठीक है, अगर मैं लाइब्रेरी में इसका उपयोग करना चाहता हूं और लाइब्रेरी का उपयोग करने वाले एक एप्लिकेशन के रूप में, अब वे दोनों लपेटे गए अपवाद पर निर्भर हैं, इसलिए यह वास्तव में मूल पुस्तकालय में होना चाहिए I हर जगह शामिल कर सकते हैं।

जो मुझे सोचता है, शायद अमरूद में मानक मानक लपेटा हुआ वर्ग कहीं है, क्योंकि अब मैं गुवा को डिफ़ॉल्ट रूप से निर्भरता के रूप में शामिल करता हूं। तो मैं सिर्फ

throw new WrappedException(e); 

या

throw Exceptions.wrap(e); 

या

Exceptions.rethrow(e); 

मैं सिर्फ अमरूद में चारों ओर देखा और Throwables जो Throwables.propagate() कि समान दिखता है पाया है, लेकिन यह सिर्फ लपेटता जांचे हुए अपवादों कर सकते हैं RuntimeException के एक विशेष उप-वर्ग के बजाय RuntimeException में।

कौन सा दृष्टिकोण बेहतर है? क्या मुझे RuntimeException की तुलना में एक विशेष लपेटा अपवाद का उपयोग नहीं करना चाहिए? मेरा शीर्ष-स्तरीय कोड शीर्षतम अपवाद जानना चाहता है जो सूचनात्मक मूल्य जोड़ता है।

यदि मेरे पास एक रनटाइम अपवाद है जो एक NullEoinception को लपेटता है जो एक NullPointerException को लपेटता है, तो रैपिंग रनटाइम अपवाद सूचनात्मक मूल्य नहीं जोड़ता है, और मुझे इसकी परवाह नहीं है, इसलिए त्रुटि जो मैं लॉग करूंगा वह गंदा अपवाद होगा।

यदि मेरे पास एक अवैध आर्ग्यूमेंट अपवाद है जो एक गंदा अपवाद को लपेटता है, तो IllegalArgumentException आम तौर पर सूचनात्मक मूल्य जोड़ता है।

तो मेरी शीर्ष कोड है कि त्रुटि लॉगिंग करता है, मैं इस तरह कुछ करने के लिए चाहते हैं:

catch (RuntimeException re) 
{ 
    logError(getTheOutermostUsefulException(re)); 
} 

/** 
* heuristics to tease out whether an exception 
* is wrapped just for the heck of it, or whether 
* it has informational value 
*/ 
Throwable getTheOutermostUsefulException(RuntimeException re) 
{   
    // subclasses of RuntimeException should be used as is 
    if (re.getClass() != RuntimeException) 
     return re; 
    // if a runtime exception has a message, it's probably useful 
    else if (re.getMessage() != null) 
     return re; 
    // if a runtime exception has no cause, it's certainly 
    // going to be more useful than null 
    else if (re.getCause() == null) 
     return re; 
    else 
     return re.getCause(); 
} 

दर्शन मेरे लिए सही लगता है, लेकिन कार्यान्वयन बुरा लगता है। लपेटा अपवादों को संभालने का कोई बेहतर तरीका है?


संबंधित प्रश्नों:

+2

लॉग के अलावा, आपके शीर्ष-स्तरीय हैंडलिंग कोड क्या करते हैं? जब आप एक जंजीर अपवाद के स्टैक ट्रेस को लॉग करते हैं, तो आपको वैसे भी पूरा निशान मिल जाता है, इसलिए इससे कोई फर्क नहीं पड़ता कि यह लपेटा गया है या नहीं। – artbristol

+0

यदि आप अभी लॉगिंग कर रहे हैं, तो आप सब कुछ लॉग इन करने जा रहे हैं, और यदि आप कुछ वास्तविक हैंडलिंग कर रहे हैं, तो केवल उन अपवादों को अनदेखा करने का प्रयास करें जिन्हें आप संभाल सकते हैं। 'getCause' आपको केवल अनचाहे करने की आवश्यकता है। – trutheality

+0

@artbristol, @trutheality: हाँ, मैंने केवल RuntimeException पर logError() को कॉल करने के बारे में सोचा था। लेकिन मेरे आवेदन में 'logError() 'का एक और हिस्सा उपयोगकर्ता को एक डिस्प्ले है, और मुझे वास्तव में बिना किसी शोर के सबसे उपयोगी संदेश प्रदर्शित करने की आवश्यकता है; वे क्या गलत हो गए, यह जानने के लिए अपवाद स्टैक के माध्यम से नहीं जा रहे हैं, बल्कि वे संदेश देखने जा रहे हैं, और यदि वे स्वयं को समस्या का पता लगा सकते हैं, तो अन्यथा मुझे " मुझे एक रनटाइम अपवाद मिला, मैं क्या करूँ? " –

उत्तर

7

स्प्रिंग केवल पुस्तकालय मैं अपेक्षाकृत कुछ इसी तरह के साथ के बारे में पता है। उन्होंने अपवादों को निहित किया है: NestedRuntimeException और NestedCheckedException। इन अपवादों में getMostSpecificCause() या contains(Class exType) जैसी उपयोगी विधियां हैं। उनकी getMessage() विधि कारण का संदेश लौटाती है (यदि रैपिंग अपवाद में पहले से कोई संदेश है तो यह जोड़ा गया है)।

इसका उपयोग वसंत के डेटा एक्सेस अपवाद पदानुक्रम में किया जाता है। विचार यह है कि प्रत्येक डेटाबेस विक्रेता अपने जेडीबीसी ड्राइवरों में विभिन्न अपवादों का खुलासा करता है। वसंत उनको पकड़ता है और उन्हें अधिक सामान्य DataAccessExceptions में अनुवाद करता है। इसका एक अन्य लाभ यह है कि चेक अपवाद स्वचालित रूप से रनटाइम अपवादों में अनुवादित होते हैं।

कहा जा रहा है कि यह बहुत जटिल कोड नहीं है, और मुझे यकीन है कि आप अपने कोड बेस में कुछ ऐसा कर सकते हैं। बस इसके लिए वसंत निर्भरता जोड़ने की जरूरत नहीं है।

यदि मैं आप थे, तो मैं जल्द ही अपवादों को "अनचाहे" करने की कोशिश नहीं करता, जब तक आप वास्तव में उन्हें वहां और वहां संभाल नहीं सकते। मैं उन्हें ग्लोबल अपवाद हैडलर के साथ बुलबुला (लपेटा या नहीं) देता हूं जो उनके कारण श्रृंखला को देखता है, पहला "सार्थक" अपवाद पाता है, और एक बुद्धिमान त्रुटि संदेश निकालता है। ऐसा करने में असमर्थ होने पर, मैं बस "तकनीकी त्रुटि" प्रिंट करता हूं और त्रुटि संदेश के विवरण में या किसी प्रकार के लॉग में पूरे स्टैक ट्रेस को बग रिपोर्ट उद्देश्य के लिए जोड़ता हूं। फिर आप बग को ठीक करेंगे और/या इसके बजाय एक और सार्थक अपवाद फेंक देंगे।

अमरूद के Throwables.getCausalChain() भी अपवाद हैंडलिंग सरल करने के लिए ब्याज की हो सकती है:

Iterables.filter(Throwables.getCausalChain(e), IOException.class)); 

संपादित करें:

मैं अपनी समस्या के बारे में थोड़ा और सोचा, और मुझे लगता है कि तुम सच में चिंता नहीं करनी चाहिए एक विशिष्ट "WrapperException" प्रकार के साथ अपने अपवाद लपेटने के बारे में। आपको सबसे ज्यादा समझने के लिए उन्हें लपेटना चाहिए: या तो एक साधारण RuntimeException (गुवा का Throwables.propagate() वहां उपयोगी हो सकता है), एक अतिरिक्त त्रुटि संदेश के साथ RuntimeException, या उपयुक्त होने पर अधिक अर्थपूर्ण अपवाद प्रकार।

जावा का कारण श्रृंखला तंत्र आपको रूट कारण तक पहुंचने देगा। आपको अपने कोड में हर जगह अपवाद रैपिंग के बारे में चिंता करने की आवश्यकता नहीं है। इसे प्रबंधित करने के लिए एक वैश्विक अपवाद हैंडलर लिखें, और हर जगह मानक अपवाद बबलिंग का उपयोग करें।

0

सामान्य रूप से, अनचेक अपवाद के साथ चेक अपवादों को लपेटने से बचने के लिए सबसे अच्छा है (here और here देखें)।कुछ मायनों में यह चारों ओर पाने के लिए:

  1. उपयोग Callable बजाय Runnable
  2. Executors ढांचे बोहेमियन की तरह का सुझाव दिया है का उपयोग करें
  3. उपवर्ग Runnable (या जो भी अंतरफलक/वर्ग का उपयोग कर रहे हैं) और जाँच करने के लिए किसी तरह जोड़ने तथ्य के बाद दौड़ के दौरान अपवादों के लिए, शायद एक विधि public Exception getRunException() या इसी तरह के।

आप एक जाँच अपवाद लपेट करना आवश्यक है, मैं सबसे अच्छा तरीका यह है कि आप पहले से ही यह कर, RuntimeException का एक उपवर्ग को परिभाषित करने के लिए है लगता है। लेकिन अगर संभव हो तो मैं इससे बचने की कोशिश करूंगा।

+2

मुझे लगता है कि रननेबल चेक अपवादों को लपेटने की आवश्यकता को दर्शाने के लिए सिर्फ एक उदाहरण था। –

+0

@Steven: yup, आपको यह मिला –

+0

मुझे लगता है, मैंने अपना जवाब संशोधित किया –

संबंधित मुद्दे