कैच ब्लॉक के अंदर फेंका गया अपवाद - क्या इसे फिर से पकड़ा जाएगा?


180

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

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

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


2
शायद आप "विषम व्यवहार" का वर्णन कर सकते हैं?
जेफरी एल व्हाइटलेज

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

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

जवाबों:


214

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


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

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

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

यह @ user3705478 पर निर्भर करता है, यदि ब्लॉक RuntimeExceptionसे फेंक दिया जाता है तो catchकोई संकलन त्रुटि नहीं होगी।
रैंडी द देव

@AndrewDunn मुझे नहीं लगता कि user3705478 का सवाल क्या है, बल्कि यह है कि क्या होता है, अगर कोई चाइल्ड अपवाद क्लॉज से पहले पैरेंट अपवाद catchक्लॉज को सूचीबद्ध किया जाए । मेरी समझ यह है कि जावा इसे नापसंद करता है, और यह संकलन के समय पकड़ा जाता है। catch
क्रिस जस्टर-यंग

71

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

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");
        }
    }
}

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

IOException को पकड़ने में: class java.io.IOException
अंत में
थ्रेड में अपवाद "मुख्य" java.lang.RuntimeException
        Catch.main (Catch.java:8) पर

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

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

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


3
एक से बचने का सबसे स्पष्ट तरीका finallyहै, ज़ाहिर है, कॉल करना System.exit। :-P
क्रिस जेस्टर-यंग

3
@ क्रिस जस्टर-यंग for(;;);छोटा है, भाषा के भीतर निहित है, साइड-इफेक्ट के रास्ते में ज्यादा परिचय नहीं देता है और, मेरे लिए, अधिक स्पष्ट है।
टॉम हॉल्टिन -

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

28

जावा भाषा विनिर्देश धारा 14.19.1 में कहता है:

यदि मान V को फेंकने के कारण ट्राई ब्लॉक का निष्पादन अचानक पूरा हो जाता है, तो एक विकल्प है:

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

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

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

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


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

6

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

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

और अब आपका कंपाइलर आप पर चिल्लाएगा नहीं :)


4

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


2

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


2

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

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

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

1

नहीं, चूंकि सभी कैच एक ही ट्रायल ब्लॉक को संदर्भित करते हैं, इसलिए कैच ब्लॉक के भीतर से फेंकने को एन्क्लोजिंग ट्राई ब्लॉक द्वारा पकड़ा जाएगा (संभवतः इस विधि में जिसे यह कहा जाता है)


-4

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

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

5
यह एक टिप्पणी होना चाहिए और एक जवाब नहीं होना चाहिए। यह वास्तविक प्रश्न को संबोधित करने के तरीके में कुछ भी नहीं प्रदान करता है - यह ओपीएस प्रश्न का सिर्फ एक समालोचक है।
डेरेक डब्ल्यू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.