java error click - هل يتم تنفيذ حظر نهائي دائمًا في جافا؟





15 Answers

كود المثال:

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

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

انتاج:

finally trumps return. 
0
for details مشكلة

بالنظر إلى هذا الكود ، هل يمكنني أن أكون متأكداً تمامًا من أن الجزء finally تنفيذه دائمًا ، بغض النظر عن something() ما something() ؟

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



ها هي الكلمات الرسمية من مواصفات لغة جافا.

14.20.2. إعدام المحاولة وأخيرًا

يتم تنفيذ عبارة try مع كتلة في finally عن طريق تنفيذ كتلة try أولاً. ثم هناك خيار:

  • إذا اكتمل تنفيذ كتلة try طبيعي ، [...]
  • إذا اكتمل تنفيذ كتلة try فجأة بسبب throw القيمة V ، [...]
  • إذا اكتمل تنفيذ كتلة try فجأة لأي سبب آخر R ، فسيتم تنفيذ الحظر finally . ثم هناك خيار:
    • إذا اكتمل الشكل النهائي بشكل طبيعي ، try عبارة try فجأة للسبب R.
    • في حالة اكتمال كتلة finally فجأة للسبب S ، فإن عبارة try تكتمل فجأة للسبب S ( والسبب R يتم تجاهله ).

مواصفات return الواقع تجعل هذا صريحًا:

JLS 14.17 بيان الإرجاع

ReturnStatement:
     return Expression(opt) ;

يحاول بيان return بدون Expression نقل التحكم إلى invoker من الأسلوب أو منشئ يحتوي عليه.

يحاول بيان return مع Expression نقل التحكم إلى منشئ الأسلوب الذي يحتوي عليه؛ تصبح قيمة Expression قيمة استدعاء الأسلوب.

تشير الأوصاف السابقة إلى " محاولات نقل التحكم " بدلاً من " التحكّم في التحكّم " فقط لأنه إذا كانت هناك أية عبارات try ضمن الأسلوب أو المُنشئ الذي تحتوي كتله المحولة على بيان return ، فسيتم تنفيذ أي عبارات أخيرة من عبارات try هذه ، النظام ، الأعمق إلى الأبعد ، قبل أن يتم نقل السيطرة إلى منشئ الأسلوب أو منشئ. يمكن للانهيار المفاجئ لبند finally أن يعطل نقل السيطرة الذي بدأه بيان return .




جربت المثال أعلاه بتعديل طفيف

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 إلى i ثم يتم تنفيذ System.out .

بعد تنفيذ حظر finally ، يُرجع مربع try 2 ، بدلاً من إرجاع 12 ، لأن بيان الإرجاع هذا لم يتم تنفيذه مرة أخرى.

إذا قمت بتصحيح هذه التعليمة البرمجية في Eclipse ، فستحصل على شعور بأنه بعد تنفيذ System.out في finally يتم تنفيذ بيان return الخاص بـ block try مرة أخرى. ولكن هذا ليس هو الحال. ببساطة إرجاع القيمة 2.




هذه هي الفكرة الكاملة لكتلة أخيرة. فهو يتيح لك التأكد من قيامك بالتنظيفات التي قد يتم تخطيها لأنك تعود ، من بين أمور أخرى ، بالطبع.

وأخيراً يتم استدعاؤه بغض النظر عما يحدث في كتلة المحاولة ( إلا إذا قمت باستدعاء System.exit(int) أو تم تشغيل Java Virtual Machine لسبب آخر).







لا ، ليست دائمًا حالة استثناء واحدة // 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");
        }
    }
}



وأخيرًا ، يتم دائمًا تشغيل هذا هو بيت القصيد ، لمجرد ظهوره في الشفرة بعد أن لا تعني العودة أن هذه هي الطريقة التي يتم تنفيذها بها. يتحمل وقت تشغيل Java مسؤولية تشغيل هذا الرمز عند الخروج من كتلة try .

على سبيل المثال ، إذا كان لديك ما يلي:

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

سيولد وقت التشغيل شيء كالتالي:

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

إذا تم طرح استثناء غير محظور فسيتم تشغيل الحظر finally وسيستمر التكرار في الانتشار.




باختصار ، في وثائق جافا الرسمية (اضغط here ) ، هو مكتوب أن -

إذا تم إنهاء JVM أثناء تنفيذ محاولة أو رمز الالتقاط ، فقد لا يتم تنفيذ الحظر النهائي. وبالمثل ، إذا تمت مقاطعة أو تنفيذ سلسلة تنفيذ المحاولة أو رمز الالتقاط ، فقد لا يتم تنفيذ الحظر النهائي حتى إذا استمر التطبيق ككل.




نعم سوف يطلق عليه. هذا هو بيت القصيد من الكلمة أخيرا. إذا كان القفز من كتلة المحاولة / الالتقاط يمكن أن يتخطى الحظر النهائي ، فهو نفس وضع System.out.println خارج المحاولة / المصيد.




نعم. فقط الحالة لن تكون JVM مخارج أو أعطال




الجواب بسيط نعم .

إدخال:

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



لأنه يتم دائما استدعاء النهائي في أي حالة لديك. ليس لديك استثناء ، لا يزال يطلق عليه ، والاستيلاء على الاستثناء ، ما زال يطلق عليه




إذا تم طرح استثناء ، يدير أخيرا. إذا لم يتم طرح استثناء ، يدير أخيرا. إذا تم القبض على الاستثناء ، يدير أخيرا. إذا لم يتم اكتشاف الاستثناء ، يدير أخيرا.

المرة الوحيدة التي لا يتم تشغيلها هي عندما تخرج JVM.




خذ بعين الاعتبار البرنامج التالي:

public class someTest {

    private static StringBuilder sb = new StringBuilder();

    public static void main(String args[]) {

        System.out.println(someString());
        System.out.println("---AGAIN---");
        System.out.println(someString());
    }

    private static String someString() {

        try {
            sb.append("-abc-");
            return sb.toString();

        } finally {
            sb.append("xyz");
        }
    }
}

اعتبارًا من Java 1.8.162 ، فإن كتلة الكود أعلاه تعطي الناتج التالي:

-abc-
---AGAIN---
-abc-xyz-abc-

هذا يعني أن استخدام finally لتحرير الكائنات هو ممارسة جيدة مثل الكود التالي:

private static String someString() {

    StringBuilder sb = new StringBuilder();

    try {
        sb.append("abc");
        return sb.toString();

    } finally {
        sb = null;
    }
}



جرب هذا الكود ، ستفهم أن الكود في النهاية يتم تنفيذه بعد بيان الإعادة .

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



Related