2009-10-30 17 views
11

(देर संपादित करें:। यह सवाल उम्मीद है कि अप्रचलित हो जाएगा जब जावा 7 "final rethrow" feature जो seems like it will be added की वजह से आता है)मेरा सुरक्षित पुनर्स्थापन कितना सुरक्षित है?


अक्सर

, मैं अपने आप को इस तरह देख स्थितियों में मिल:

 
    do some initialization 
    try { 
     do some work 
    } catch any exception { 
     undo initialization 
     rethrow exception 
    } 

सी # में आप इस तरह यह कर सकते हैं:

InitializeStuff(); 
try 
{ 
    DoSomeWork(); 
} 
catch 
{ 
    UndoInitialize(); 
    throw; 
} 

जावा के लिए, कोई अच्छा प्रतिस्थापन नहीं है, और the proposal for improved exception handling was cut from Java 7 के बाद से, ऐसा लगता है कि जब तक हमें ऐसा कुछ नहीं मिलता है तब तक यह कई वर्षों तक ले जाएगा।

(संपादित करें::। आधा एक साल बाद, final rethrow is back, या तो ऐसा लगता है)

public final class Rethrow { 

    private Rethrow() { throw new AssertionError("uninstantiable"); } 

    /** Rethrows t if it is an unchecked exception. */ 
    public static void unchecked(Throwable t) { 
     if (t instanceof Error) 
      throw (Error) t; 
     if (t instanceof RuntimeException) 
      throw (RuntimeException) t; 
    } 

    /** Rethrows t if it is an unchecked exception or an instance of E. */ 
    public static <E extends Exception> void instanceOrUnchecked(
      Class<E> exceptionClass, Throwable t) throws E, Error, 
      RuntimeException { 
     Rethrow.unchecked(t); 
     if (exceptionClass.isInstance(t)) 
      throw exceptionClass.cast(t); 
    } 

} 

विशिष्ट उपयोग:

public void doStuff() throws SomeException { 
    initializeStuff(); 
    try { 
     doSomeWork(); 
    } catch (Throwable t) { 
     undoInitialize(); 
     Rethrow.instanceOrUnchecked(SomeException.class, t); 
     // We shouldn't get past the above line as only unchecked or 
     // SomeException exceptions are thrown in the try block, but 
     // we don't want to risk swallowing an error, so: 
     throw new SomeException("Unexpected exception", t); 
    } 
    private void doSomeWork() throws SomeException { ... } 
} 

यह एक है इस प्रकार, मैं अपने खुद के रोल करने का निर्णय लिया बिट वर्डी, Throwable को पकड़ना आम तौर पर फंस जाता है, मैं अपवाद को फिर से मिटाने के लिए प्रतिबिंब का उपयोग करने में वास्तव में खुश नहीं हूं, और मुझे हमेशा थोड़ा असहज लेखन लगता है "यह नहीं होगा" टिप्पणियां, लेकिन व्यवहार में यह काम करता है ell (या कम से कम लगता है)। मुझे आश्चर्य है कि:

  1. क्या मेरे पास मेरी रीथ्रो सहायक विधियों में कोई त्रुटियां हैं? कुछ कोने के मामलों में मुझे याद आया है? (मुझे पता है कि Throwable कुछ इतनी गंभीर है कि मेरी undoInitialize असफल हो जायेगी की वजह से किया गया हो सकता है, लेकिन यह ठीक है।)
    • कोई पहले से ही इस आविष्कार किया गया है? मैंने कॉमन्स लैंग के ExceptionUtils को देखा लेकिन यह अन्य चीजें करता है।

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

  • finally ड्रायड मैं तलाश कर रहा हूँ नहीं है। अपवाद फेंकने पर मुझे केवल सामान करने में दिलचस्पी है।
  • हाँ, मैं पकड़ने पता Throwable है एक बड़ा नहीं-नहीं, लेकिन मुझे लगता है कि कम बुराई यहाँ तीन कैच खंड समान कोड के साथ (Error, RuntimeException और SomeException, क्रमशः के लिए) होने की तुलना में है।
  • ध्यान दें कि मैं किसी भी त्रुटि को दबाने की कोशिश नहीं कर रहा हूँ - विचार यह है कि किसी भी अपवाद try ब्लॉक में फेंक दिया बुलबुला अप करने के लिए कॉल स्टैक के माध्यम से जैसे ही मुझे कुछ चीजें rewinded किया है जारी रहेगा है।
+1

आपके पास थ्रोबल को पकड़ने के लिए एक अच्छा तर्क है। इसे नीचे जाने मत दो। यह गोटो के उपयोग की तरह है, "इसका उपयोग कभी न करें, जब तक आपको करना न पड़े।" –

उत्तर

5

इसे संभालने के कुछ तरीके हैं। पहली बार मेरी वरीयता है यदि आपको यह जानने की आवश्यकता नहीं है कि अपवाद क्या था।

boolean okay = false; 
try { 
    // do some work which might throw an exception 
    okay = true; 
} finally { 
    if (!okay) // do some clean up. 
} 

कुछ मामलों में आप एक ही एक अतिरिक्त चर के बिना, क्या कोशिश ब्लॉक करता है के आधार पर कर सकते हैं।

दूसरा विकल्प एक हैक है लेकिन यह भी काम करता है।

try { 
    // do some work which might throw an exception 
} catch (Throwable t) { 
    // do something with t. 
    Thread.currentThread().stop(t); 
} 

स्टॉप (फेंकने योग्य टी) विधि धागा नहीं रुकती, बजाय यह एक अनियंत्रित तरीके से उपलब्ध कराई गई अपवाद फेंकने के लिए धागा कारण बनता है।

आप कुछ परेशानियों के साथ Unsafe.throwException() का उपयोग कर सकते हैं और जेनेरिक के साथ ऐसा करने का एक तरीका है जिसे मैं भूल गया हूं।

1

यदि आप अपने अनियंत्रण होने के बारे में चिंतित हैं तो आप उस कोड को आखिरकार ब्लॉक में रखना चाहते हैं, जैसे कि इसे किसी बिंदु पर बुलाया जाना चाहिए, तो आपको शायद हमेशा साफ करना चाहिए।

मैं कुछ अपवादों के रूप में Throwable को पकड़ने के लिए तैयार हूं, और कुछ मैं बस लॉग इन करता हूं, क्योंकि उपयोगकर्ता का कुछ भी नहीं कर सकता है, जैसे NullPointerException

लेकिन, आप नहीं दिखा था क्या SomeException के रूप में परिभाषित किया गया है, लेकिन अगर एक OutOfMemoryException फेंक दिया जाता है, अपने फेंकने योग्य इसके शिकार हो सकते हैं, लेकिन यह एक ही प्रकार नहीं हो सकता है के रूप में SomeException तो अपने आवरण अपने नमूना समारोह में की आवश्यकता होगी , कम से कम जब मैं instanceOrUnchecked विधि को देखता हूं।

आप एक यूनिट परीक्षण लिखना चाहते हैं, अपवादों के विभिन्न वर्गों को आजमा सकते हैं और देख सकते हैं कि अपेक्षित रूप से क्या काम करता है या नहीं, इसलिए आप अपेक्षित व्यवहार दस्तावेज कर सकते हैं।

+0

'कुछ अपवाद अपवाद बढ़ाता है'। 'आखिरकार' में अनियंत्रित होने के लिए - मैं केवल अपवाद शुरू करना चाहता हूं यदि कोई अपवाद फेंक दिया जाता है। मैं निश्चित रूप से एक बुलियन ध्वज झूठा सेट कर सकता था और फिर इसे 'try' ब्लॉक में आखिरी चीज़ के रूप में सत्य के रूप में सेट कर सकता था, लेकिन यह थोड़ा बोझिल है (और क्या होगा अगर किसी के बारे में सोचने के बाद कोई भी कोड जोड़ता है अपवाद हैंडलिंग?)। – gustafc

+0

इसके अलावा, मैंने इसका परीक्षण किया है, और यह बहुत अच्छी तरह से काम करता है ... सभी परिस्थितियों में मैं सोचने में सक्षम हूं, जो केवल साबित करता है कि मैंने कोड लिखने में कामयाब रहा है, मैं खुद को तोड़ने के लिए पर्याप्त बुद्धिमान नहीं हूं =) – gustafc

+1

क्या आपने ऐसी कक्षा के साथ परीक्षण किया है जो थ्रोवेबल को बढ़ाता है, न कि अपवाद को बढ़ाता है? –

1

एक वैकल्पिक केवल तभी कारण एक जाँच अपवाद नहीं है एक कारखाने जो SomeException बनाता है:

public static SomeException throwException(String message, Throwable cause) throws SomeException { 
     unchecked(cause); //calls the method you defined in the question. 
     throw new SomeException(message, cause); 
    } 

कारण है कि मैं विधि में वापसी मान में डाल है ताकि ग्राहक कुछ कर सकते हैं इस तरह:

 catch (Throwable e) { 
     undoInitialize(); 
     throw SomeException.throwException("message", e); 
    } 

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

आपके कोड पर इसका नुकसान यह है कि यह कम पोर्टेबल है (यह कुछ अपवाद के लिए काम करता है, लेकिन कुछ अन्य निष्पादन के लिए नहीं), लेकिन यह ठीक हो सकता है, क्योंकि यह आपके द्वारा आवश्यक प्रत्येक अपवाद प्रकार के लिए नहीं होगा एक पूर्ववत प्रारंभ करें।

यदि यह आपके उपयोग के मामले में फिट बैठता है तो आप कुछ अपवाद के निर्माता में अनचेक कॉल डाल सकते हैं और सभी उप-वर्गों में तर्क उपलब्ध हो सकते हैं, लेकिन इसे आपके विशिष्ट प्रोजेक्ट में फिट होना होगा - यह सामान्य में एक अच्छा विचार नहीं होगा मामला क्योंकि यह रनटाइम अपवादों को लपेटने से रोक देगा।

 public SomeException(message, cause) { 
      super(message, unchecked(cause)); 
     } 

     private static Throwable unchecked(Throwable cause) { 
      if (cause instanceof Error) throw (Error) cause; 
      if (cause instanceof RuntimeException) throw (RuntimeException) cause; 
      return cause; 
     } 
+0

फ़ैक्टरी फ़ंक्शन अच्छा है, लेकिन चूंकि मेरे पास अपवाद पदानुक्रम है ('कुछ अपवाद' को विस्तारित करने वाले कई वर्ग), मुझे कुछ और लचीला चाहिए। मुझे दूसरे विकल्प की चतुरता पसंद है, लेकिन मुझे लगता है कि यह बहुत चालाक है - रखरखाव प्रोग्रामर के लिए डब्ल्यूटीएफ क्षमता उच्च लगती है। – gustafc

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