अपवाद को पकड़ में फेंक दिया और अंत में खंड


155

विश्वविद्यालय में जावा के लिए एक प्रश्न पर, इस कोड का स्निपेट था:

class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}

public class C1 {
    public static void main(String[] args) throws Exception {
        try {
            System.out.print(1);
            q();
        }
        catch (Exception i) {
            throw new MyExc2();
        }
        finally {
            System.out.print(2);
            throw new MyExc1();
        }
    }

    static void q() throws Exception {
        try {
            throw new MyExc1();
        }
        catch (Exception y) {
        }
        finally {
            System.out.print(3);
            throw new Exception();
        }
    }
}

मुझे इसका आउटपुट देने के लिए कहा गया। मैंने उत्तर दिया 13Exception in thread main MyExc2, लेकिन सही उत्तर है 132Exception in thread main MyExc1। ऐसा क्यों है? मैं अभी समझ नहीं पा रहा हूं कि कहां जाता है MyExc2

जवाबों:


167

आपके उत्तर को पढ़ने और यह देखने के आधार पर कि आप कैसे इसके साथ आने की संभावना रखते हैं, मेरा मानना ​​है कि आपको लगता है कि "अपवाद-प्रगति" में "प्राथमिकता" है। याद रखो:

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

ध्यान दें कि लागू कैच या अंत में ब्लॉक शामिल हैं:

जब कोई नया अपवाद कैच ब्लॉक में डाला जाता है, तो नया अपवाद अभी भी उस कैच के अंत में ब्लॉक के अधीन होता है, यदि कोई हो।

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


7
«आपके उत्तर को पढ़ने और यह देखने के आधार पर कि आप कैसे इसके साथ आने की संभावना रखते हैं, मेरा मानना ​​है कि आपको लगता है कि" अपवाद-प्रगति "में" पूर्वता "है» धन्यवाद ... यह बिल्कुल मेरा विचार था :)
जुबस्तफ

39

विकिपीडिया आखिर खंड के बारे में क्या कहता है:

अधिक सामान्य एक संबंधित क्लॉज (अंत में, या सुनिश्चित करना) है जिसे निष्पादित किया जाता है चाहे अपवाद हुआ हो या नहीं, आमतौर पर अपवाद-हैंडलिंग ब्लॉक के शरीर के भीतर अधिग्रहीत संसाधनों को जारी करने के लिए।

चलो अपने कार्यक्रम को भंग करें।

try {
    System.out.print(1);
    q();
}

तो, 1स्क्रीन में आउटपुट हो जाएगा, फिर q()कहा जाता है। में q(), एक अपवाद फेंका गया है। अपवाद तब पकड़ा जाता है Exception yलेकिन यह कुछ नहीं करता है। अंत में एक खंड को निष्पादित किया जाता है (इसे), इसलिए, 3स्क्रीन पर मुद्रित किया जाएगा। क्योंकि (विधि q()में) अंतिम खंड में फेंका गया एक अपवाद है , q()विधि भी माता-पिता के ढेर के अपवाद को पार करती है ( throws Exceptionविधि घोषणा में) new Exception()द्वारा फेंक दिया जाएगा और इसके द्वारा पकड़ा जाएगा catch ( Exception i ), MyExc2अपवाद को फेंक दिया जाएगा (अभी के लिए इसे अपवाद स्टैक में जोड़ें ), लेकिन अंत में mainब्लॉक में पहले निष्पादित किया जाएगा।

तो में,

catch ( Exception i ) {
    throw( new MyExc2() );
} 
finally {
    System.out.print(2);
    throw( new MyExc1() );
}

अंत में एक क्लॉज कहा जाता है ... (याद रखें, हमने अभी पकड़ा Exception iऔर फेंका है MyExc2) संक्षेप में, 2स्क्रीन पर मुद्रित होता है ... और स्क्रीन पर मुद्रित होने के बाद 2, एक MyExc1अपवाद फेंक दिया जाता है। विधि MyExc1द्वारा नियंत्रित किया जाता है public static void main(...)

आउटपुट:

"थ्रेड में मुख्य अपवाद MyExc1"

व्याख्याता सही है! :-)

संक्षेप में , यदि आप एक है अंत में आज़माएं / कैच खंड में, एक अंत में (निष्पादित किया जाएगा के बाद अपवाद को पकड़ने से पहले पकड़ा अपवाद बाहर फेंक)


catchके बाद से क्रियान्वित किया जाता है q()एक फेंक दिया Exceptionअपनी ही से finallyब्लॉक।
Péter Török

"Q () में, एक अपवाद फेंका गया है, लेकिन अपवाद को पूरी तरह से फेंक दिए जाने से पहले, एक अंत में क्लॉज को पहले निष्पादित किया जाता है, इसलिए, 3 को स्क्रीन पर प्रिंट किया जाएगा।" एर ... नहीं, qपास निष्पादन में फेंका गया पहला अपवाद है। खाली catchब्लॉक q(जिसमें यह अपवाद निगल जाता है), फिर finallyब्लॉक में q। अंत में प्रिंट ब्लॉक ने कहा 3, फिर एक नया अपवाद है, जो करने के लिए धन्यवाद फेंकता qके throws Exceptionमाता-पिता के लिए ढेर अप पारित कर दिया है।
पॉवरलॉर्ड

38

अंत में अपवाद कैच ब्लॉक में अपवादों को छोड़ते हैं।

जावा भाषा विनिर्देश 14 संस्करण से उद्धरण :

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

  • यदि अंत में ब्लॉक सामान्य रूप से पूरा हो जाता है, तो प्रयास विवरण आर के लिए अचानक पूरा हो जाता है।

  • यदि अंत में कारण एस के लिए अचानक पूरा हो जाता है, तो कोशिश का बयान एस (और कारण आर को त्याग दिया जाता है) के लिए अचानक पूरा हो जाता है।


21

अंत में क्लॉज को तब भी निष्पादित किया जाता है, जब अपवाद को कोशिश / कैच ब्लॉक में कहीं से फेंक दिया जाता है।

क्योंकि यह अंतिम रूप से निष्पादित किया जाता है mainऔर यह एक अपवाद फेंकता है, यही अपवाद है जो कॉलर्स देखते हैं।

इसलिए यह सुनिश्चित करने का महत्व है कि finallyखंड कुछ भी नहीं फेंकता है, क्योंकि यह tryब्लॉक से अपवादों को निगल सकता है ।


5
ईवीईएन को भी अंजाम दिया जाएगा अगर कोशिश / कैच ब्लॉक में कोई अपवाद नहीं है
नंद

2
+1: प्रत्यक्ष और उस बिंदु के बिना पूरे स्टैक को नीचे किए बिना जिसे ओपी पहले से ही समझने लगता है।
पॉवरलॉर्ड

9

एक ही समय में दो अपवाद methodनहीं हो सकते throw। यह हमेशा अंतिम फेंक दिया जाएगा exception, जो इस मामले में यह हमेशा finallyब्लॉक से एक होगा ।

जब विधि से पहला अपवाद q()फेंक दिया जाता है, तो इसे पकड़ा जाएगा और फिर अंत में फेंके गए अपवाद को निगल लिया जाएगा।

q () -> फेंक दिया new Exception -> main catch Exception -> throw new Exception -> finally एक नया फेंक exception(और catch"खो दिया है" से एक )


3

यह सोचने का सबसे आसान तरीका कल्पना है कि पूरे आवेदन के लिए एक चर वैश्विक है जो वर्तमान अपवाद को पकड़ रहा है।

Exception currentException = null;

जैसा कि प्रत्येक अपवाद को फेंक दिया जाता है, "currentException" उस अपवाद पर सेट होती है। जब अनुप्रयोग समाप्त होता है, यदि currentException! = Null है, तो रनटाइम त्रुटि की रिपोर्ट करता है।

इसके अलावा, अंत में ब्लॉक हमेशा विधि से बाहर निकलने से पहले चलते हैं। फिर आपको कोड स्निपेट की आवश्यकता हो सकती है:

public class C1 {

    public static void main(String [] argv) throws Exception {
        try {
            System.out.print(1);
            q();

        }
        catch ( Exception i ) {
            // <-- currentException = Exception, as thrown by q()'s finally block
            throw( new MyExc2() ); // <-- currentException = MyExc2
        }
        finally {
             // <-- currentException = MyExc2, thrown from main()'s catch block
            System.out.print(2);
            throw( new MyExc1() ); // <-- currentException = MyExc1
        }

    }  // <-- At application exit, currentException = MyExc1, from main()'s finally block. Java now dumps that to the console.

    static void q() throws Exception {
        try {
            throw( new MyExc1() ); // <-- currentException = MyExc1
        }
        catch( Exception y ) {
           // <-- currentException = null, because the exception is caught and not rethrown
        }
        finally {
            System.out.print(3);
            throw( new Exception() ); // <-- currentException = Exception
        }
    }
}

वह क्रम जिसमें आवेदन निष्पादित होता है:

main()
{
  try
    q()
    {
      try
      catch
      finally
    }
  catch
  finally
}

1

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

चीयर्स।

/////////////Return dont always return///////

try{

    return "In Try";

}

finally{

    return "In Finally";

}

////////////////////////////////////////////


////////////////////////////////////////////    
while(true) { 

    try {

        return "In try";

   } 

   finally{

        break;     

    }          
}              
return "Out of try";      
///////////////////////////////////////////


///////////////////////////////////////////////////

while (true) {     

    try {            

        return "In try";    

     } 
     finally {   

         continue;  

     }                         
}
//////////////////////////////////////////////////

/////////////////Throw dont always throw/////////

try {

    throw new RuntimeException();

} 
finally {

    return "Ouuuups no throw!";

}
////////////////////////////////////////////////// 

1
class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}

public class C1 {
    public static void main(String[] args) throws Exception {
        try {
            System.out.print("TryA L1\n");
            q();
            System.out.print("TryB L1\n");
        }
        catch (Exception i) {
            System.out.print("Catch L1\n");                
        }
        finally {
            System.out.print("Finally L1\n");
            throw new MyExc1();
        }
    }

    static void q() throws Exception {
        try {
            System.out.print("TryA L2\n");
            q2();
            System.out.print("TryB L2\n");
        }
        catch (Exception y) {
            System.out.print("Catch L2\n");
            throw new MyExc2();  
        }
        finally {
            System.out.print("Finally L2\n");
            throw new Exception();
        }
    }

    static void q2() throws Exception {
        throw new MyExc1();
    }
}

गण:

TryA L1
TryA L2
Catch L2
Finally L2
Catch L1
Finally L1        
Exception in thread "main" MyExc1 at C1.main(C1.java:30)

https://www.compilejava.net/


1
हालांकि यह कोड स्निपेट समाधान हो सकता है, स्पष्टीकरण सहित वास्तव में आपके पोस्ट की गुणवत्ता में सुधार करने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए सवाल का जवाब दे रहे हैं, और उन लोगों को आपके कोड सुझाव के कारणों का पता नहीं चल सकता है
राहुल गुप्ता

1

तर्क छपाई खत्म होने तक स्पष्ट है 13। इसके बाद फेंके गए अपवाद q()को पकड़ लिया जाता catch (Exception i)है main()और new MyEx2()उसे फेंकने के लिए तैयार किया जाता है। हालांकि, अपवाद को फेंकने से पहले, finallyब्लॉक को पहले निष्पादित करना होगा। तब आउटपुट बन जाता है 132और finallyएक अन्य अपवाद को फेंकने के लिए कहता है new MyEx1()

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

इस प्रकार, इस कार्यक्रम में, अपवाद MyEx2को निगल लिया जाता है और MyEx1फेंक दिया जाता है। यह अपवाद बाहर फेंक दिया जाता है main()और अब पकड़ा नहीं जाता है, इस प्रकार जेवीएम बंद हो जाता है और अंतिम आउटपुट होता है 132Exception in thread main MyExc1

संक्षेप में, यदि आप एक है finallyएक में try/catchखंड, एक finallyनिष्पादित किया जाएगा अपवाद को पकड़ने के बाद , लेकिन इससे पहले कि किसी भी पकड़ा अपवाद फेंक , और केवल नवीनतम अपवाद अंत में फेंक दिया होगा


0

मुझे लगता है कि आपको सिर्फ finallyब्लॉक चलना है :

  1. प्रिंट "1"।
  2. finallyमें qप्रिंट "3"।
  3. finallyमें mainप्रिंट "2"।

0

इस तरह की स्थिति को संभालने के लिए यानी अंत में ब्लॉक द्वारा उठाए गए अपवाद को संभालना। आप अंत में ब्लॉक को कोशिश ब्लॉक से घेर सकते हैं: अजगर में नीचे दिए गए उदाहरण को देखें:

try:
   fh = open("testfile", "w")
   try:
      fh.write("This is my test file for exception handling!!")
   finally:
      print "Going to close the file"
      fh.close()
except IOError:
   print "Error: can\'t find file or read data"

-1

मुझे लगता है कि इससे समस्या हल हो जाएगी:

boolean allOk = false;
try{
  q();
  allOk = true;
} finally {
  try {
     is.close();
  } catch (Exception e) {
     if(allOk) {
       throw new SomeException(e);
     }
  }
}

3
आप "हल" करने के लिए क्या समस्या ले जा रहे हैं? क्या आपको परीक्षा में प्रश्न का मतलब है? अच्छी तरह से यह पहले से ही जवाब दिया। यदि आपको दिए गए कोड की समस्या का मतलब है, क्योंकि यह सिर्फ एक परीक्षा का प्रश्न है, तो इसे दोष देने का कोई अर्थ नहीं है।
पृथ्वी इंजन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.