java - आखिरकार जावा में हमेशा अवरुद्ध हो जाता है?




return try-catch-finally (20)

इस कोड को ध्यान में रखते हुए, क्या मैं पूरी तरह से सुनिश्चित हो सकता हूं कि finally ब्लॉक हमेशा निष्पादित होता है, इससे कोई फर्क नहीं पड़ता कि something() क्या है?

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("i don't know if this will get printed out.");
}

जवाब सरल है हाँ

इनपुट:

try{
    int divideByZeroException = 5 / 0;
} catch (Exception e){
    System.out.println("catch");
    return;    // also tried with break; in switch-case, got same output
} finally {
    System.out.println("finally");
}

उत्पादन:

catch
finally


अंत में हमेशा निष्पादित करें कि क्या अपवाद हैंडल है या नहीं। अगर किसी भी अपवाद को ब्लॉक करने से पहले अपवाद हुआ तो आखिरकार ब्लॉक निष्पादित नहीं होगा।


अंततः हमेशा निष्पादित किया जाता है जब तक कि असामान्य प्रोग्राम समाप्ति न हो (जैसे System.exit (0) को कॉल करना ..)। तो, आपका sysout मुद्रित हो जाएगा


अन्य प्रतिक्रियाओं के अतिरिक्त, यह इंगित करना महत्वपूर्ण है कि 'आखिरकार' को किसी भी अपवाद / लौटाए गए मूल्य को .. कैच ब्लॉक द्वारा ओवरराइड करने का अधिकार है। उदाहरण के लिए, निम्नलिखित कोड 12 देता है:

public static int getMonthsInYear() {
    try {
        return 10;
    }
    finally {
        return 12;
    }
}

इसी प्रकार, निम्न विधि अपवाद नहीं फेंकती है:

public static int getMonthsInYear() {
    try {
        throw new RuntimeException();
    }
    finally {
        return 12;
    }
}

जबकि निम्न विधि इसे फेंक देती है:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}

आखिरकार ब्लॉक का यही विचार है। यह आपको यह सुनिश्चित करने देता है कि आप क्लीनअप करते हैं जो अन्यथा छोड़े जा सकते हैं क्योंकि आप अन्य चीज़ों के साथ वापस आते हैं।

अंत में प्रयास ब्लॉक में क्या होता है इस पर ध्यान दिए बिना ( जब तक आप System.exit(int) या जावा वर्चुअल मशीन को किसी अन्य कारण से बाहर नहीं निकालते)।


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

उदाहरण के लिए यदि आपके पास निम्नलिखित हैं:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

रनटाइम इस तरह कुछ उत्पन्न करेगा:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

यदि एक अनिश्चित अपवाद फेंक दिया जाता है तो finally ब्लॉक चल जाएगा और अपवाद प्रचार जारी रहेगा।


इस कोड को आज़माएं, आप समझेंगे कि अंत में ब्लॉक को रिटर्न स्टेटमेंट के बाद निष्पादित किया जाएगा

public class TestTryCatchFinally {
    static int x = 0;

    public static void main(String[] args){
        System.out.println(f1() );
        System.out.println(f2() );
    }

    public static int f1(){
        try{
            x = 1;
            return x;
        }finally{
            x = 2;
        }
    }

    public static int f2(){
        return x;
    }
}

इसके बारे में सोचने का एक तार्किक तरीका है:

  1. आखिरकार ब्लॉक में रखा गया कोड निष्पादित किया जाना चाहिए जो कोशिश ब्लॉक के भीतर होता है
  2. तो यदि कोशिश ब्लॉक में कोड किसी मान को वापस करने या अपवाद फेंकने का प्रयास करता है तो आइटम को 'शेल्फ पर' रखा जाता है जब तक अंत में ब्लॉक निष्पादित नहीं हो जाता
  3. चूंकि अंत में ब्लॉक में कोड (परिभाषा के अनुसार) एक उच्च प्राथमिकता है, जो इसे पसंद या वापस फेंक सकता है। किस मामले में 'शेल्फ पर' छोड़ा गया कुछ भी त्याग दिया जाता है।
  4. इसका एकमात्र अपवाद यह है कि यदि वीएम प्रयास प्रणाली के दौरान पूरी तरह से बंद हो जाता है जैसे 'System.exit'

इसे निष्पादन के सामान्य पाठ्यक्रम (यानी बिना किसी अपवाद के फेंक दिए) पर विचार करें: यदि विधि 'शून्य' नहीं है तो यह हमेशा स्पष्ट रूप से कुछ देता है, फिर भी, अंततः हमेशा निष्पादित हो जाता है


ऐसा इसलिए है क्योंकि आपने मेरे मान को 12 के रूप में असाइन किया है, लेकिन मैंने फ़ंक्शन में मेरा मान वापस नहीं किया है। सही कोड निम्नानुसार है:

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}

क्योंकि जब तक आप System.exit() (या थ्रेड क्रैश) को कॉल नहीं करते हैं, तब तक अंततः ब्लॉक को तब तक बुलाया जाएगा।


जावा भाषा विशिष्टता से आधिकारिक शब्द यहां दिए गए हैं।

14.20.2। आखिरकार कोशिश करें और आखिरकार कोशिश करें

finally ब्लॉक के साथ एक try कथन पहले try ब्लॉक को निष्पादित करके निष्पादित किया जाता है। फिर एक विकल्प है:

  • यदि try ब्लॉक का निष्पादन सामान्य रूप से पूरा हो जाता है, [...]
  • यदि एक try वी के throw के कारण try ब्लॉक का निष्पादन अचानक समाप्त हो जाता है, [...]
  • यदि किसी भी अन्य कारण आर के लिए try ब्लॉक का निष्पादन अचानक समाप्त हो जाता है, तो finally ब्लॉक निष्पादित किया जाता है। फिर एक विकल्प है:
    • यदि अंत में ब्लॉक सामान्य रूप से पूरा हो जाता है, तो try कथन कारण आर के लिए अचानक समाप्त हो जाता है।
    • यदि finally ब्लॉक कारण एस के लिए अचानक समाप्त हो जाता है, तो try कथन कारण एस ( और कारण आर को त्याग दिया जाता है ) के लिए अचानक समाप्त हो जाता है

return लिए विनिर्देश वास्तव में यह स्पष्ट करता है:

जेएलएस 14.17 रिटर्न स्टेटमेंट

ReturnStatement:
     return Expression(opt) ;

कोई Expression कोई return स्टेटमेंट उस विधि या कन्स्ट्रक्टर के आवेदक को नियंत्रण स्थानांतरित करने का प्रयास करता है जिसमें यह शामिल है।

Expression साथ एक return स्टेटमेंट उस विधि के आवेदक को नियंत्रण स्थानांतरित करने का प्रयास करता है जिसमें वह शामिल है; Expression का मूल्य विधि आमंत्रण का मूल्य बन जाता है।

पिछले विवरणों में " नियंत्रण स्थानांतरित करने " के बजाय " नियंत्रण स्थानांतरित करने का प्रयास " होता है क्योंकि यदि विधि या कन्स्ट्रक्टर के भीतर कोई भी try कथन है, जिसका try ब्लॉक में return स्टेटमेंट होता है, तो finally उन प्रयासों के खंडों को खंडित किया जाएगा, ऑर्डर, बाहरी से सबसे ऊपर, नियंत्रण से पहले विधि या कन्स्ट्रक्टर के आवेदक को स्थानांतरित कर दिया जाता है। finally खंड के पूर्ण होने से return स्टेटमेंट द्वारा शुरू किए गए नियंत्रण के हस्तांतरण में बाधा return है।


नहीं, हमेशा एक अपवाद मामला नहीं है // System.exit (0); अंत में ब्लॉक अंततः निष्पादित होने से पहले रोकता है।

  class A {
    public static void main(String args[]){
        DataInputStream cin = new DataInputStream(System.in);
        try{
            int i=Integer.parseInt(cin.readLine());
        }catch(ArithmeticException e){
        }catch(Exception e){
           System.exit(0);//Program terminates before executing finally block
        }finally{
            System.out.println("Won't be executed");
            System.out.println("No error");
        }
    }
}

मैंने उपरोक्त उदाहरण को मामूली संशोधन के साथ करने की कोशिश की-

public static void main(final String[] args) {
    System.out.println(test());
}

public static int test() {
    int i = 0;
    try {
        i = 2;
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
    }
}

उपरोक्त कोड आउटपुट:

आखिरकार ट्रम्प वापस आते हैं।
2

ऐसा इसलिए है क्योंकि जब return i; निष्पादित किया गया है i पास एक मूल्य है 2. इसके बाद finally ब्लॉक निष्पादित किया जाता है जहां 12 को आवंटित किया जाता है और फिर System.out आउट निष्पादित किया जाता है।

finally ब्लॉक करने के बाद 12 को वापस करने के बजाय, ब्लॉक रिटर्न 2 को रोकने का try , क्योंकि यह रिटर्न स्टेटमेंट फिर से निष्पादित नहीं होता है।

यदि आप ग्रहण में इस कोड को डीबग करेंगे तो आपको एक एहसास होगा कि finally System.out ब्लॉक को निष्पादित करने के बाद try ब्लॉक के return स्टेटमेंट को फिर से निष्पादित किया जाता है। पर ये स्थिति नहीं है। यह बस मूल्य 2 देता है।


यह वास्तव में किसी भी भाषा में सच है ... आखिरकार रिटर्न स्टेटमेंट से पहले निष्पादित होगा, इससे कोई फर्क नहीं पड़ता कि वह तरीका विधि निकाय में कहां है। यदि यह मामला नहीं था, तो अंत में ब्लॉक का अधिक अर्थ नहीं होगा।


हाँ इसे बुलाया जाएगा। आखिरकार कीवर्ड रखने का यह पूरा बिंदु है। यदि कोशिश / पकड़ ब्लॉक से बाहर कूदना अंततः ब्लॉक को छोड़ सकता है तो यह कोशिश / पकड़ के बाहर System.out.println डालने जैसा ही था।


हाँ यह होगा। केवल मामला यह जेवीएम बाहर निकलना या दुर्घटनाग्रस्त नहीं होगा


हां, finally कोशिश या पकड़ कोड ब्लॉक के निष्पादन के बाद बुलाया जाएगा।

finally केवल एक बार नहीं कहा जाएगा:

  1. यदि आप System.exit() आह्वान करते हैं;
  2. यदि JVM पहले क्रैश हो जाता है;
  3. यदि JVM try या catch ब्लॉक में एक अनंत लूप (या कुछ अन्य गैर-बाधा रहित, गैर-समाप्ति बयान) तक पहुंचता है;
  4. यदि ओएस जबरन जम्मू प्रक्रिया को समाप्त कर देता है; उदाहरण के लिए यूनिक्स पर "kill -9"।
  5. अगर मेजबान प्रणाली मर जाती है; उदाहरण के लिए बिजली की विफलता, हार्डवेयर त्रुटि, ओएस आतंक, आदि।
  6. अगर आखिर में ब्लॉक को डेमॉन थ्रेड द्वारा निष्पादित किया जा रहा है और अन्य सभी गैर डिमन थ्रेड बाहर निकलने से पहले बाहर निकलते हैं।

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





try-catch-finally