Javaのfinallyステートメントを使用する場合の注意点

零下一度
リリース: 2017-06-25 10:44:15
オリジナル
1550 人が閲覧しました

インターネット上では、Java の例外キャッチ メカニズムの try...catch...finally ブロック内のfinally ステートメントが確実に実行されるかどうかについて議論している人がたくさんいます。多くの人はノーと答えますが、もちろん彼らの答えは正しいです。私の実験の結果、finally ステートメントが実行されない状況が少なくとも 2 つあります。

(1) try ステートメントの前など、try ステートメントが実行されない。これは、finally ステートメントを実行するための必要条件ではあるが、対応する try ステートメントが実行される必要があることも示しています。

(2) try ブロックに System.exit(0); のような文があり、JVM も停止され、すべてが終了します。 finally ステートメントも実行されません。

もちろん、Finally ステートメントの実行と return の関係については多くの人が議論していますが、非常に混乱しています。私も混乱しています。彼らが言ったことは正しいとは思いません。finally ステートメントは、try return ステートメントが実行された後、return が返される前に実行されます。この記述は少し矛盾しているかもしれませんが、それを裏付けるために、以下にいくつかの結果と例を示します。

1.finally ステートメントは、return ステートメントの実行後、return の前に実行されます。

Javaのfinallyステートメントを使用する場合の注意点
public class FinallyTest1 {

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

    public static int test1() {
        int b = 20;

        try {
            System.out.println("try block");

            return b += 80; 
        }
        catch (Exception e) {

            System.out.println("catch block");
        }
        finally {
            
            System.out.println("finally block");
            
            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }
        }
        
        return b;
    }
    
}
ログイン後にコピー
Javaのfinallyステートメントを使用する場合の注意点

実行結果は、

try block
finally block
b>25, b = 100
100
ログイン後にコピー
ログイン後にコピー

return文が実行されてからfinally文が実行されたことを意味しますが、直接返されるわけではありませんが、 finally ステートメントが実行されて結果が返されるのを待ちます。

この例では状況を説明するのに十分ではないと思われる場合は、結論を強化するために別の例を示します:

Javaのfinallyステートメントを使用する場合の注意点
public class FinallyTest1 {

    public static void main(String[] args) {
        
        System.out.println(test11());
    }
    
    public static String test11() {
        try {
            System.out.println("try block");

           return test12();
      } finally {
           System.out.println("finally block");
       }
  }

  public static String test12() {
       System.out.println("return statement");

       return "after return";
   }
    
}
ログイン後にコピー
Javaのfinallyステートメントを使用する場合の注意点

実行結果は次のとおりです:

try block
return statement
finally block
after return
ログイン後にコピー

説明try の return ステートメントは最初に実行されますが、すぐには戻りません。finally の実行が完了するまで待機します。finally にも return ステートメントがある場合、try の return は直接返されないのではないかと思われるかもしれません。下を見てください。

2.finally ブロックの return ステートメントは、try ブロックの return ステートメントをオーバーライドします。

Javaのfinallyステートメントを使用する場合の注意点
public class FinallyTest2 {

    public static void main(String[] args) {

        System.out.println(test2());
    }

    public static int test2() {
        int b = 20;

        try {
            System.out.println("try block");

            return b += 80;
        } catch (Exception e) {

            System.out.println("catch block");
        } finally {

            System.out.println("finally block");

            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }

            return 200;
        }

        // return b;
    }

}
ログイン後にコピー
Javaのfinallyステートメントを使用する場合の注意点
実行結果は次のとおりです:

try block
finally block
b>25, b = 100
200
ログイン後にコピー
これは、try に return ステートメントがあるかどうかに関係なく、最終的に return が直接返されることを示しています。ここでの詳細は、return tofinally を追加した後、finally の外側の return b は到達不能なステートメントになる、つまり実行できないため、コメントアウトする必要があることに注意してください。そうしないとコンパイラがエラーを報告します。

ここでもう一度考えてみてください。finally に return ステートメントがなくても、b の値が変更されている場合、try の return は変更された値を返すのでしょうか、それとも元の値を返しますか?下を見てください。

3.finally ステートメントに戻り値を上書きする return ステートメントがない場合、finally の変更により元の戻り値が変更される場合と変更されない場合があります。

テスト ケース 1:

Javaのfinallyステートメントを使用する場合の注意点
public class FinallyTest3 {

    public static void main(String[] args) {

        System.out.println(test3());
    }

    public static int test3() {
        int b = 20;

        try {
            System.out.println("try block");

            return b += 80;
        } catch (Exception e) {

            System.out.println("catch block");
        } finally {

            System.out.println("finally block");

            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }

            b = 150;
        }

        return 2000;
    }

}
ログイン後にコピー
Javaのfinallyステートメントを使用する場合の注意点
実行結果は次のとおりです:

try block
finally block
b>25, b = 100
100
ログイン後にコピー
ログイン後にコピー

テスト ケース 2:

Javaのfinallyステートメントを使用する場合の注意点りー
Javaのfinallyステートメントを使用する場合の注意点

运行结果是:

FINALLY
ログイン後にコピー

为什么测试用例1中finally里的b = 150;并没有起到作用而测试用例2中finally的map.put("KEY", "FINALLY");起了作用而map = null;却没起作用呢?这就是Java到底是传值还是传址的问题了,具体请看精选30道Java笔试题解答,里面有详细的解答,简单来说就是:Java中只有传值没有传址,这也是为什么map = null这句不起作用。这同时也说明了返回语句是try中的return语句而不是 finally外面的return b;这句,不相信的话可以试下,将return b;改为return 294,对原来的结果没有一点影响。

这里大家可能又要想:是不是每次返回的一定是try中的return语句呢?那么finally外的return b不是一点作用没吗?请看下面。

4. try块里的return语句在异常的情况下不会被执行,这样具体返回哪个看情况。

Javaのfinallyステートメントを使用する場合の注意点
public class FinallyTest4 {

    public static void main(String[] args) {

        System.out.println(test4());
    }

    public static int test4() {
        int b = 20;

        try {
            System.out.println("try block");

            b = b / 0;

            return b += 80;
        } catch (Exception e) {

            b += 15;
            System.out.println("catch block");
        } finally {

            System.out.println("finally block");

            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }

            b += 50;
        }

        return 204;
    }

}
ログイン後にコピー
Javaのfinallyステートメントを使用する場合の注意点

运行结果是:

try block
catch block
finally block
b>25, b = 35
85
ログイン後にコピー
这里因 为在return之前发生了除0异常,所以try中的return不会被执行到,而是接着执行捕获异常的catch 语句和最终的finally语句,此时两者对b的修改都影响了最终的返回值,这时return b;就起到作用了。当然如果你这里将return b改为return 300什么的,最后返回的就是300,这毋庸置疑。

这里大家可能又有疑问:如果catch中有return语句呢?当然只有在异常的情况下才有可能会执行,那么是在finally之前就返回吗?看下面。

5. 当发生异常后,catch中的return执行情况与未发生异常时try中return的执行情况完全一样。

Javaのfinallyステートメントを使用する場合の注意点
public class FinallyTest5 {

    public static void main(String[] args) {

        System.out.println(test5());
    }

    public static int test5() {
        int b = 20;

        try {
            System.out.println("try block");
            
            b = b /0;

            return b += 80;
        } catch (Exception e) {

            System.out.println("catch block");
            return b += 15;
        } finally {

            System.out.println("finally block");

            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }

            b += 50;
        }

        //return b;
    }

}
ログイン後にコピー
Javaのfinallyステートメントを使用する場合の注意点

运行结果如下:

try block
catch block
finally block
b>25, b = 35
35
ログイン後にコピー

说明了发生异常后,catch中的return语句先执行,确定了返回值后再去执行finally块,执行完了catch再返回,finally里对b的改变对返回值无影响,原因同前面一样,也就是说情况与try中的return语句执行完全一样。

 

最后总结:finally块的语句在try或catch中的return语句执行之后返回之前执行且finally里的修改语句可能影响也可能不影响try或catch中 return已经确定的返回值,若finally里也有return语句则覆盖try或catch中的return语句直接返回。

学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群:159610322   我们一起学Java!

以上がJavaのfinallyステートメントを使用する場合の注意点の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート