2008-09-27 17 views
125

यह प्रोग्रामिंग 101 प्रश्न की तरह प्रतीत हो सकता है और मैंने सोचा था कि मुझे जवाब पता था लेकिन अब मुझे खुद को दोबारा जांचने की आवश्यकता है। नीचे दिए गए कोड के इस टुकड़े में, क्या पहले कैच ब्लॉक में फेंक दिया गया अपवाद नीचे सामान्य अपवाद कैच ब्लॉक द्वारा पकड़ा जाएगा?कैच ब्लॉक के अंदर फेंक दिया गया अपवाद - क्या इसे फिर से पकड़ा जाएगा?

try { 
    // Do something 
} catch(IOException e) { 
    throw new ApplicationException("Problem connecting to server"); 
} catch(Exception e) { 
    // Will the ApplicationException be caught here? 
} 

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

+1

शायद आप "विचित्र व्यवहार का वर्णन कर सकता है "? –

+0

क्या आप सुनिश्चित हैं कि एप्लिकेशन अपवाद को कहीं और नहीं फेंक दिया जा रहा है और इस ब्लॉक तक प्रचारित किया जा रहा है? – sblundy

+0

मैंने इसे अपने ग्रहण आईडीई में देखा। यह कोशिश करने के लिए मुझे "नई अपवाद फेंकने" के लिए मजबूर करने के लिए मजबूर कर रहा है लेकिन मुझे नहीं पता कि क्यों। मैंने इसे अतीत में ऐसा करने के बिना किया है। मुझे नहीं लगता कि एक प्रयास ब्लॉक की आवश्यकता क्यों होगी। Google पर कई उदाहरण दिखाते हैं कि लोगों को कोशिश करने की आवश्यकता नहीं है। क्या ऐसा इसलिए है क्योंकि मैं एक कथन के अंदर फेंक रहा हूं? – djangofan

उत्तर

169

नहीं, चूंकि नया throwtry ब्लॉक में सीधे नहीं है।

+0

आइए कहें कि कोड इस की तरह है { } पकड़ें (अपवाद ई) { System.err.println ("पकड़ अपवाद:" + e.getClass()); } पकड़ें (IOException ई) { System.err.println ("पकड़ IOException:" + e.getClass()); } और कोशिश ब्लॉक में कोड IO अपवाद उत्पन्न करता है, क्या यह तत्काल सामान्य अपवाद ब्लॉक पर जाएगा या यह IOException पकड़ ब्लॉक पर उड़ जाएगा? – user3705478

+2

@ user3705478 कोड उस तरह की ग़लत स्थिति से बचने के लिए संकलित नहीं करेगा। आम तौर पर, आपको उसी प्रयास ब्लॉक में अपने सुपरक्लास को पकड़ने के बाद उप-वर्ग के लिए पकड़ने की अनुमति नहीं है। –

+0

धन्यवाद। तो मुझे एक संकलन समय त्रुटि मिलेगी, है ना? जब मैं घर जाता हूं तो मैं इसका परीक्षण करूंगा। – user3705478

3

नहीं - जैसा कि क्रिस जेस्टर-यंग ने कहा, इसे पदानुक्रम में अगले प्रयास में फेंक दिया जाएगा।

1

जैसा कि ऊपर कहा ...
मैं जोड़ना होगा कि यदि आप मुसीबत को देखकर क्या, चल रहा है अगर आप डीबगर में इस मुद्दे को दोबारा नहीं कर सकता है, तो आप नया अपवाद फिर से फेंकने से पहले एक निशान में जोड़ सकते हैं (अच्छी पुरानी System.out.println के साथ बदतर में, लॉग 4j जैसी अच्छी लॉग सिस्टम के साथ अन्यथा)।

55

नहीं। यह जांचना बहुत आसान है।

public class Catch { 
    public static void main(String[] args) { 
     try { 
      throw new java.io.IOException(); 
     } catch (java.io.IOException exc) { 
      System.err.println("In catch IOException: "+exc.getClass()); 
      throw new RuntimeException(); 
     } catch (Exception exc) { 
      System.err.println("In catch Exception: "+exc.getClass()); 
     } finally { 
      System.err.println("In finally"); 
     } 
    } 
} 

प्रिंट चाहिए:

 
In catch IOException: class java.io.IOException 
In finally 
Exception in thread "main" java.lang.RuntimeException 
     at Catch.main(Catch.java:8)

तकनीकी तौर पर है कि एक संकलक बग, कार्यान्वयन निर्भर, अनिर्दिष्ट व्यवहार, या कुछ और हो सकता था। हालांकि, जेएलएस बहुत अच्छी तरह से खींचा गया है और कंपेलर इस तरह की साधारण चीज़ के लिए काफी अच्छे हैं (जेनेरिक कोने का मामला एक अलग मामला हो सकता है)।

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

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

+2

'अंततः' से बचने का सबसे स्पष्ट तरीका निश्चित रूप से 'System.exit' को कॉल करने के लिए है। :- पी –

+2

@ क्रिस जेस्टर-यंग 'के लिए (;;);' भाषा में निहित छोटा है, साइड इफेक्ट्स के रास्ते में बहुत कुछ नहीं पेश करता है, और मेरे लिए, अधिक स्पष्ट है। –

+0

'System.exit' सीपीयू के लिए मित्रवत है! : -ओ लेकिन हाँ, ठीक है, स्पष्ट रूप से यह एक व्यक्तिपरक मानदंड है। इसके अलावा, मैं आपको कोड गोल्फर होने के बारे में नहीं जानता था। ;-) –

1

यह दूसरे पकड़ ब्लॉक द्वारा पकड़ा नहीं जाएगा। प्रत्येक अपवाद केवल एक कोशिश ब्लॉक के अंदर पकड़ा जाता है। आप घोंसला हालांकि कोशिश करता है (नहीं है कि यह आम तौर पर एक अच्छा विचार है) कर सकते हैं:

try { 
    doSomething(); 
} catch (IOException) { 
    try { 
     doSomething(); 
    } catch (IOException e) { 
     throw new ApplicationException("Failed twice at doSomething" + 
     e.toString()); 
    }   
} catch (Exception e) { 
} 
+0

मैंने एक समान कोड लिखा था। लेकिन मुझे विश्वास नहीं है। मैं अपने कैच ब्लॉक में थ्रेड.sleep() को कॉल करना चाहता हूं। लेकिन Thread.sleep खुद को एक interruptedException फेंकता है। क्या यह सही है (एक सर्वोत्तम अभ्यास) ऐसा करने के लिए जैसा कि आपने अपने उदाहरण में दिखाया है? – riroo

1

नहीं है, के बाद से कैच सब, एक ही कोशिश ब्लॉक को देखें तो एक कैच ब्लॉक के भीतर से फेंक एक संलग्न कोशिश ब्लॉक द्वारा पकड़ा किया जाएगा

26

जावा भाषा विशिष्टता खंड 14.19.1 में कहते हैं (शायद विधि है कि यह एक कहा जाता है में):

कोशिश ब्लॉक के निष्पादन एक मूल्य के वी के थ्रो की वजह से अचानक पूरा करता है, तो अगर एक विकल्प है:

  • यदि रन-टाइम प्रकार वी वी कोशिश कथन के किसी भी पकड़ खंड के पैरामीटर को असाइन करने योग्य है, तो पहला (बाएं) ऐसा कैच क्लॉज चुना जाता है। मान V चयनित कैच क्लॉज के पैरामीटर को असाइन किया गया है, और उस पकड़ खंड का ब्लॉक निष्पादित किया गया है। यदि वह ब्लॉक सामान्य रूप से पूरा होता है, तो प्रयास कथन सामान्य रूप से पूरा होता है; यदि वह ब्लॉक किसी भी कारण से अचानक समाप्त हो जाता है, तो प्रयास कथन उसी कारण से अचानक समाप्त हो जाता है।

संदर्भ: http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134

दूसरे शब्दों में, पहले enclosing पकड़ अपवाद करता है, और अगर एक अपवाद है कि पकड़ से बाहर निकाल दिया जाता है, कि किसी भी के दायरे में नहीं है संभाल कर सकते हैं कि मूल प्रयास के लिए अन्य पकड़, इसलिए वे इसे संभालने की कोशिश नहीं करेंगे।

एक संबंधित और भ्रमित करने वाली चीज़ यह जानना है कि एक कोशिश में [पकड़] - अंतिम रूप से संरचना, आखिरकार ब्लॉक एक अपवाद फेंक सकता है और यदि ऐसा है, तो कोशिश या पकड़ ब्लॉक द्वारा फेंक दिया गया कोई अपवाद खो गया है। यह पहली बार भ्रमित हो सकता है जब आप इसे देखते हैं।

+0

बस जावा 7 के बाद से जोड़ना चाहता था आप संसाधनों के साथ 'try'-use का उपयोग कर इससे बच सकते हैं। फिर, यदि 'कोशिश करें' और 'आखिरकार' दोनों फेंक दें, 'आखिरकार' दबा दिया गया है, लेकिन 'try' से अपवाद के लिए भी जोड़ा गया है।यदि 'पकड़' भी फेंकता है, तो आप भाग्यशाली नहीं हैं, जब तक कि आप इसे 'addSuppressed' के माध्यम से स्वयं को संभाल नहीं लेते और 'try' अपवाद जोड़ते हैं - तो आपके पास तीनों हैं। –

5

यदि आप कैच ब्लॉक से अपवाद फेंकना चाहते हैं तो आपको अपनी विधि/कक्षा/आदि को सूचित करना होगा। कि यह अपवाद फेंकने की जरूरत है। इसलिए जैसा:

public void doStuff() throws MyException { 
    try { 
     //Stuff 
    } catch(StuffException e) { 
     throw new MyException(); 
    } 
} 

और अब अपने संकलक आप पर चिल्लाना नहीं होगा :)

-2

पुरानी पोस्ट लेकिन "ई" चर अद्वितीय होना चाहिए:

try { 
    // Do something 
} catch(IOException ioE) { 
    throw new ApplicationException("Problem connecting to server"); 
} catch(Exception e) { 
    // Will the ApplicationException be caught here? 
} 
+3

यह एक टिप्पणी होना चाहिए और उत्तर नहीं होना चाहिए। यह वास्तविक प्रश्न को संबोधित करने के तरीके में कुछ भी नहीं प्रदान करता है - यह सिर्फ ओपीएस प्रश्न की आलोचना है। –

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