关于java:try / finally没有catch和返回值

try/finally without catch and return value

本问题已经有最佳答案,请猛点这里访问。

我有一个计划如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main {
    public static void main(String[] args)throws Exception
    {
        int res = test();
        System.out.println("after call , res =" + res) ;
    }

    public static int test()throws Exception
    {
        try
        {
            return 10/0;
        }
        finally
        {
            System.out.println("finally") ;
        }
    }
}

运行上述程序后,在控制台中看到以下结果:

1
2
3
4
finally
Exception in thread"main" java.lang.ArithmeticException: / by zero
    at Main.test(Main.java:17)
    at Main.main(Main.java:7)

此行为正常,因为向主方法引发异常。

然后我将代码更改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Main {
    public static void main(String[] args)throws Exception
    {
        int res = test();
        System.out.println("after call , res =" + res) ;
    }

    public static int test()throws Exception
    {
        try
        {
            return 10/0;
        }
        finally
        {
            System.out.println("finally") ;
            return 20;
        }
    }
}

当运行上述程序时,我在控制台中看到以下结果:

1
2
finally
after call , res = 20

我的问题与第二种格式有关。为什么当返回finally块时,异常不被抛出到main方法?


当抛出异常时,它将首先通过您的finally块。

如果您的finally块没有返回或抛出任何内容,则会传递原始异常。

另一方面,如果您的finally块返回一个值,那么异常就不会再传播。

  • 参考:JLS关于Try Finally

最后看看try catch的执行情况。

从Java语言规范JLS-1420.2

If the run-time type of V is not assignment compatible with a catchable exception class of any catch clause of the try statement, then the finally block is executed. Then there is a choice:

If the finally block completes normally, then the try statement completes abruptly because of a throw of the value V.

If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and the throw of value V is discarded and forgotten).


来自JLS(Emphasis Mine):

If execution of the try block completes abruptly because of a throw of
a value V, then there is a choice:
[...]
If the run-time type of V is not assignment compatible with a catchable exception class of any catch clause of the try statement, then the finally
block is executed. Then there is a choice:

  • If the finally block completes normally, then the try statement completes abruptly because of a throw of the value V.

  • If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and the throw of value V is
    discarded and forgotten).

这意味着,如果在finally块中使用return,该方法将返回而不引发异常。

return外,还有其他一些语句会导致finally块突然完成并忽略异常。它们在JLS第14.1节中定义。基本上,它是breakcontinuereturn或异常(抛出或由语句/方法引起)。然后,完整的try/catch/finally块就完成了。

try/catch/finally的规范中还有一些情况,特别是在没有异常或存在匹配catch子句的情况下。归根结底,finallycatchtry


  • 如果在finally部分中使用return,则会丢失异常。方法将以返回值的普通类型完成。
  • 如果您不在finally部分中使用return,在您的情况下,方法将异常完成。
  • 第一种情况:

    1
    2
    3
    4
    5
    6
    try {
        throw new Exception();
    } finally {
        //Exception will be lost, normal shutdown of the method
        return;
    }

    第二种情况:

    1
    2
    3
    4
    5
    try {
        throw new Exception();
    } finally {
        //Exception won't be lost, we'll get Exception in the main method
    }

    第三种情况:

    1
    2
    3
    4
    5
    6
    try {
        throw new Exception();
    } finally {
        throw new IOException();
        // we lost Exception, IOException will be thrown
    }

    注意:使用finally节抛出异常或返回值是一种糟糕的做法。例如,此部分是为关闭外部资源而创建的。


    finally块中的所有内容都是在引发异常之前执行的,因此如果返回finally块,则不会引发异常。出于这个原因,从finally块返回通常是一个坏主意。

    看看这个博客,了解一些关于这个的信息。


    In first program when ArithmeticException occur in try block then call the finally block and after execute the finally block , exception occur . because exception is not handled by program .
    Second Program when finally block execute after that return statement execute and no exception occur because after the return statement execute compiler return in main method and remaining execution will not execute in finally block . So exception will not occur .


    因为finally块总是被执行的,不管是否发生异常,如果您从finally方法返回,那么您将把您的执行发送到调用方法,并且您将丢失异常。所以它也会产生警告。

    enter image description here


    在第一种情况下,finally块作为其行为执行,但它没有捕获异常,而是通过main方法抛出异常。通过这个例子检查它

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class HelloWorld{

         public static void main(String []args)throws Exception
         {
            try
            {
            int res = test();
            System.out.println("after call , res =" + res) ;
            }
            catch(Exception ex)
            {
                System.out.println("Main Catch") ;
            }
         }
         public static int test()throws Exception
         {
            try
            {
                return 10/0;
            }
            finally
            {
                System.out.println("finally") ;
            }
        }
    }

    在上述代码中,执行了Main Catch

    在第二种情况下,您返回了数字,因此主方法中没有异常。


    如果你读JavaDOC,那么它会说,

    它允许程序员避免清理代码被返回、继续或中断意外绕过。将清理代码放在finally块中始终是一个好的实践,即使在没有预料到异常的情况下也是如此。

    因此,如果在finally块之后放置清理代码,那么如果有异常,就不会调用它。


    The return statementin the finally block was basically stopping the
    exception that happened in the try block from propagating up even
    though it wasn't caught.

    但是Java编译器在编写这段代码时确实会发出警告。虽然return statements应始终位于try block中,而finally区块对于releasing/closing connections, pointers etc.是不稳定的。

    这似乎是Java的行为方式。

    看看这里


    Java的EDCOX1 0不总是返回,这可能会娱乐。