最终是否总是在Java中执行?

时间:2020-03-05 18:54:05  来源:igfitidea点击:

考虑到这段代码,我可以绝对确定无论" something()"是什么," finally"块总是可以执行吗?

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

解决方案

回答

是的,在执行try或者catch代码块之后,将调用finally

最终不会被调用的唯一时间是:

  • 如果我们调用System.exit();
  • 如果JVM首先崩溃;
  • 如果JVM在try或者catch块中达到了无限循环(或者其他不间断,不终止的语句);
  • 操作系统是否强行终止了JVM进程;例如在UNIX上为" kill -9"。
  • 如果主机系统死机;例如电源故障,硬件错误,操作系统崩溃等。
  • 如果finally块将由守护程序线程执行并且所有其他非守护程序线程退出,则在调用finally之前。

回答

除非有异常的程序终止(例如调用System.exit(0)..),否则总是执行finally。因此,sysout将被打印

回答

是的,它将被调用。这就是拥有finally关键字的全部意义。如果跳出try / catch块可以跳过finally块,则与将System.out.println放在try / catch外部相同。

回答

示例代码:

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

回答

实际上,在任何语言中都是如此……最终,无论该返回在方法主体中的何处,最终总是将在return语句之前执行。如果不是这种情况,那么finally块将没有太大的意义。

回答

除非由于JVM崩溃或者对System.exit(0)的调用导致程序异常终止,否则总是执行finally块。

最重要的是,从finally块中返回的任何值都将覆盖执行finally块之前返回的值,因此在使用try finally时请务必检查所有退出点。

回答

另外,尽管这是不好的做法,但是如果finally块中有return语句,它将胜过常规块中的其他任何返回。也就是说,以下块将返回false:

try { return true; } finally { return false; }

从finally块中抛出异常也是一样。

回答

最后返回也将丢弃任何异常。 http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

回答

考虑这一点的逻辑方法是:

  • 放置在finally块中的代码必须在try块中发生的任何情况下都必须执行
  • 因此,如果try块中的代码尝试返回值或者引发异常,则将该项目"放在架子上",直到finally块可以执行为止
  • 因为finally块中的代码(根据定义)具有较高的优先级,所以它可以返回或者抛出任何喜欢的东西。在这种情况下,"架子上"剩下的任何东西都将被丢弃。
  • 唯一的例外是如果VM在try块期间完全关闭,例如通过'System.exit'

回答

除了最后要替换try块中的return的return以外,异常也是如此。引发异常的finally块将替换try块中引发的返回或者异常。

回答

我尝试对上面的示例进行了一些修改-

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.");
    }
}

上面的代码输出:

finally trumps return.

  2

这是因为执行" return i;"时," i"具有值2. 此后,执行" finally"块,其中将12分配给" i",然后执行" System.out" out。

执行完finally块后,try块返回2,而不是返回12,因为不会再次执行该return语句。

如果我们将在Eclipse中调试此代码,那么我们会感觉到,在执行finally块的System.out之后,再次执行try块的return语句。但这种情况并非如此。它只是返回值2.

回答

总而言之,总是运行finally,仅仅是因为它在返回之后出现在代码中并不意味着它就是这样实现的。 Java运行时有责任在退出try块时运行此代码。

例如,如果我们具有以下条件:

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

运行时将生成如下内容:

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

如果抛出未捕获的异常,则将运行" finally"块,并且该异常将继续传播。

回答

因为除非我们调用System.exit()(否则线程崩溃),否则将始终调用finally块。

回答

那就是finally块的整个想法。它可以确保我们进行清理,否则可能会跳过清理,因为除其他外,我们当然会返回。

无论try块中发生了什么,Finally都会被调用(除非我们调用System.exit(int)或者Java虚拟机由于其他原因而启动)。

回答

因为总决赛总是在任何情况下都被调用。我们没有异常,它仍然被称为,捕获异常,它仍然被称为

回答

除了其他响应,重要的一点是要指出,"最终"有权通过try..catch块覆盖任何异常/返回的值。例如,以下代码返回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();
    }
}

回答

在正常的执行过程中考虑这一点(即不引发任何异常):如果方法不是" void",则它总是显式返回某些内容,但最终总是被执行

回答

这是因为我们将i的值分配为12,但没有将i的值返回给函数。正确的代码如下:

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

回答

这是Java语言规范中的正式用语。

14.20.2. 最终尝试和最终捕获的执行

A try statement with a finally block is executed by first executing the try block. Then there is a choice:
  
  
  If execution of the try block completes normally, [...]
  If execution of the try block completes abruptly because of a throw of a value V, [...]
  If execution of the try block completes abruptly for any other reason R, then the finally block is executed. Then there is a choice:
  
  
  If the finally block completes normally, then the try statement completes abruptly for reason R. 
  If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).

实际上," return"的规范使这一点很明确:

JLS 14.17 return语句

ReturnStatement:
     return Expression(opt) ;

  
  A return statement with no Expression attempts to transfer control to the invoker of the method or constructor that contains it. 
  
  A return statement with an Expression attempts to transfer control to the invoker of the method that contains it; the value of the Expression becomes the value of the method invocation.
  
  The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements within the method or constructor whose try blocks contain the return statement, then any finally clauses of those try statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.