考虑到这段代码,我是否可以绝对确定 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");
}
probably
。
finally
; finalizer == finalize()
方法。
是的,finally
将在 try
或 catch
代码块执行后被调用。
唯一不会调用 finally
的时间是:
如果调用 System.exit() 如果调用 Runtime.getRuntime().halt(exitStatus) 如果 JVM 先崩溃 如果 JVM 在 try 或catch 块 如果 OS 强制终止 JVM 进程;例如,在 UNIX 上 kill -9
示例代码:
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int test() {
try {
return 0;
}
finally {
System.out.println("something is printed");
}
}
输出:
something is printed.
0
finally
子句中的语句替换为 return 2;
之外,行为是相同的(编译器错误)。
此外,虽然这是不好的做法,但如果 finally 块中有 return 语句,它将胜过常规块的任何其他 return。也就是说,以下块将返回 false:
try { return true; } finally { return false; }
从 finally 块中抛出异常也是如此。
这是 Java 语言规范中的官方用语。
14.20.2. Execution of try-finally and try-catch-finally
通过首先执行 try 块来执行带有 finally 块的 try 语句。然后有一个选择:如果 try 块的执行正常完成,[...] 如果 try 块的执行由于抛出值 V 而突然完成,[...] 如果 try 块的执行突然完成由于任何其他原因 R,然后执行 finally 块。然后有一个选择:如果 finally 块正常完成,那么 try 语句由于原因 R 突然完成。如果 finally 块由于原因 S 突然完成,那么 try 语句由于原因 S 突然完成(并且原因 R 被丢弃)。
return
的规范实际上明确说明了这一点:
JLS 14.17 The return Statement
ReturnStatement: return Expression(opt) ;没有 Expression 的 return 语句尝试将控制权转移给包含它的方法或构造函数的调用者。带有 Expression 的 return 语句试图将控制权转移给包含它的方法的调用者;表达式的值成为方法调用的值。前面的描述说的是“尝试转移控制”,而不仅仅是“转移控制”,因为如果方法或构造函数中有任何 try 语句,其 try 块包含 return 语句,那么这些 try 语句的任何 finally 子句都将被执行,在在将控制权转移到方法或构造函数的调用者之前,按从内到外的顺序。 finally 子句的突然完成可能会中断由 return 语句启动的控制转移。
除了其他响应之外,重要的是要指出“终于”有权覆盖 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();
}
}
OutOfMemoryError
? ;)
finally
块之后使用 return retVal
after 来解决它,尽管这当然假设您抑制了一些其他异常,因为否则代码将没有意义.
我尝试了上面的例子,稍作修改-
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
out。
执行 finally
块后,try
块返回 2,而不是返回 12,因为此 return 语句不再执行。
如果您将在 Eclipse 中调试此代码,那么您会感觉到在执行 finally
块的 System.out
之后再次执行 try
块的 return
语句。但这种情况并非如此。它只是返回值 2。
i
不是一个原始对象,而是一个 Integer 对象怎么办。
这是Kevin's answer的详细说明。重要的是要知道要返回的表达式是在 finally
之前计算的,即使它是在之后返回的。
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int printX() {
System.out.println("X");
return 0;
}
public static int test() {
try {
return printX();
}
finally {
System.out.println("finally trumps return... sort of");
}
}
输出:
X
finally trumps return... sort of
0
finally
之后的内容。计算返回值(此处为 printX()
)仍然在它之前。
System.out.println("finally trumps return... sort of");
替换为 System.out.print("finally trumps return in try"); return 42;
return
不会返回一些只有在调用者打印它或其他什么时才会被评估的魔法延续。 printX()
在 return
发生之前被调用,无论任何 try
/catch
或其他任何内容。
这就是 finally 块的全部想法。它可以让你确保你做的清理工作可能会因为你返回而被跳过,当然,除其他外。
不管发生什么在 try 块中最终都会被调用(除非您调用 System.exit(int)
或 Java 虚拟机因其他原因退出)。
考虑这个问题的一个合乎逻辑的方法是:
放置在 finally 块中的代码必须在 try 块中发生的任何情况下执行因此,如果 try 块中的代码尝试返回值或抛出异常,则该项目将被放置在“架子上”直到 finally 块可以执行因为代码在finally 块(根据定义)具有高优先级,它可以返回或抛出任何它喜欢的东西。在这种情况下,任何留在“架子上”的东西都会被丢弃。唯一的例外是如果虚拟机在尝试块期间完全关闭,例如通过“System.exit”
finally 总是被执行,除非有异常的程序终止(比如调用 System.exit(0)..)。所以,你的系统输出将被打印出来
不,并非总是一种例外情况是// System.exit(0);在 finally 块阻止 finally 被执行之前。
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");
}
}
}
finally 中的 return 也会抛出任何异常。 http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
除非由于 JVM 崩溃或对 System.exit(0)
的调用导致程序异常终止,否则始终会执行 finally 块。
最重要的是,从 finally 块中返回的任何值都将覆盖在 finally 块执行之前返回的值,因此在使用 try finally 时要小心检查所有退出点。
finally 总是 run 这就是重点,仅仅因为它出现在 return 之后的代码中并不意味着它就是这样实现的。 Java 运行时有责任在退出 try
块时运行此代码。
例如,如果您有以下情况:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
运行时将生成如下内容:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
如果抛出未捕获的异常,则 finally
块将运行并且异常将继续传播。
是的,它会被调用。这就是使用 finally 关键字的全部意义所在。如果跳出 try/catch 块可以跳过 finally 块,这与将 System.out.println 放在 try/catch 之外是一样的。
因为除非您调用 System.exit()
(或线程崩溃),否则将始终调用 finally 块。
简而言之,在官方 Java 文档(单击 here)中,写到 -
如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。同样,如果执行 try 或 catch 代码的线程被中断或杀死,即使应用程序作为一个整体继续运行,finally 块也可能不会执行。
这是因为您将 i 的值分配为 12,但没有将 i 的值返回给函数。正确的代码如下:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
答案很简单,是的。
输入:
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
不总是
Java 语言规范描述了 try
-catch
-finally
和 try
-catch
块如何在 14.20.2
中工作,它没有指定始终执行 finally
块。但是对于 try
-catch
-finally
和 try
-finally
块完成的所有情况,它确实指定必须在完成之前执行 finally
。
try {
CODE inside the try block
}
finally {
FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).
JLS 不保证 FIN 在 CODE 之后执行。 JLS 保证如果执行 CODE 和 NEXT,则 FIN 将始终在 CODE 之后和 NEXT 之前执行。
为什么 JLS 不保证 finally
块总是在 try
块之后执行? 因为这是不可能的。 JVM 在完成 try
块之后但在执行 finally
块之前被中止(杀死、崩溃、关闭电源)的可能性不大,但有可能。 JLS 无法避免这种情况。
因此,任何依赖于 finally
块的正确行为的软件总是在其 try
块完成后执行,这些软件都存在错误。
try
块中的 return
指令与此问题无关。如果执行到达 try
-catch
-finally
之后的代码,则保证 finally
块将在之前执行,无论 try
块内有或没有 return
指令。
any software which for their proper behaviour depends on finally blocks always being executed after their try blocks complete are bugged.
是不正确的。 finally
块通常用于资源清理以防止泄漏。否则你会怎么做?同样,您也不能(或不应该...)捕获 Error
,因为(通常)普通应用程序没有合理的方法来处理它们。
finally
可能(如果有足够的时间,可能将)导致错误,但是额外的开发(和测试)时间是否值得潜在的不明显的稳定性改进?更笼统地说:对特定设计的关注程度是否取决于所讨论的子系统?毕竟,时间是宝贵的资源。 :)
finally
块总是在返回 x
的(计算的)值之前执行。
System.out.println("x value from foo() = " + foo());
...
int foo() {
int x = 2;
try {
return x++;
} finally {
System.out.println("x value in finally = " + x);
}
}
输出:
finally 中的 x 值 = 3 x 来自 foo() 的值 = 2
是的,它会的。无论您的 try 或 catch 块中发生什么,除非另有 System.exit() 调用或 JVM 崩溃。如果块中有任何 return 语句,finally 将在该 return 语句之前执行。
是的,它会的。唯一的情况是 JVM 退出或崩溃
是的,finally 块总是执行。大多数开发人员使用这个块来关闭数据库连接、结果集对象、语句对象,并且还使用 java hibernate 来回滚事务。
finally
将执行,这是肯定的。
finally
在以下情况下不会执行:
情况1 :
当您执行 System.exit()
时。
案例2:
当您的 JVM / 线程崩溃时。
案例3:
当您手动停止执行时。
添加到 @vibhash's answer 因为没有其他答案可以解释在像下面这样的可变对象的情况下会发生什么。
public static void main(String[] args) {
System.out.println(test().toString());
}
public static StringBuffer test() {
StringBuffer s = new StringBuffer();
try {
s.append("sb");
return s;
} finally {
s.append("updated ");
}
}
将输出
某人更新
我试过这个,它是单线程的。
public static void main(String args[]) throws Exception {
Object obj = new Object();
try {
synchronized (obj) {
obj.wait();
System.out.println("after wait()");
}
} catch (Exception ignored) {
} finally {
System.out.println("finally");
}
}
main
Thread
将永远处于 wait
状态,因此永远不会调用 finally
,
所以控制台输出不会 print
String
: 在 wait()
或 finally
之后
同意@Stephen C,上面的例子是第三种情况提到here之一:
在以下代码中添加更多这样的无限循环可能性:
// import java.util.concurrent.Semaphore;
public static void main(String[] args) {
try {
// Thread.sleep(Long.MAX_VALUE);
// Thread.currentThread().join();
// new Semaphore(0).acquire();
// while (true){}
System.out.println("after sleep join semaphore exit infinite while loop");
} catch (Exception ignored) {
} finally {
System.out.println("finally");
}
}
案例2:如果JVM先崩溃
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public static void main(String args[]) {
try {
unsafeMethod();
//Runtime.getRuntime().halt(123);
System.out.println("After Jvm Crash!");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);
}
情况 6:如果 finally
块将由守护程序 Thread
执行,并且在调用 finally
之前所有其他非守护程序 Threads
退出。
public static void main(String args[]) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
printThreads("Daemon Thread printing");
// just to ensure this thread will live longer than main thread
Thread.sleep(10000);
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
};
Thread daemonThread = new Thread(runnable);
daemonThread.setDaemon(Boolean.TRUE);
daemonThread.setName("My Daemon Thread");
daemonThread.start();
printThreads("main Thread Printing");
}
private static synchronized void printThreads(String str) {
System.out.println(str);
int threadCount = 0;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
System.out.println("Thread :" + t + ":" + "state:" + t.getState());
++threadCount;
}
}
System.out.println("Thread count started by Main thread:" + threadCount);
System.out.println("-------------------------------------------------");
}
输出:这不会打印“finally”,这意味着“daemon thread”中的“Finally block”没有执行
主线程打印线程:Thread[My Daemon Thread,5,main]:state:BLOCKED 线程:Thread[main,5,main]:state:RUNNABLE 线程:Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE主线程启动的线程数:3 ------------------------------ -------- Daemon Thread 打印 Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE 主线程启动的线程数: 2 -------------------------------------------------进程以退出代码 0 结束
考虑以下程序:
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());
System.out.println("---PRINT THE RESULT---");
System.out.println(sb.toString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
从 Java 1.8.162 开始,上述代码块给出以下输出:
-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz
这意味着使用 finally
释放对象是一种很好的做法,如以下代码:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null; // Just an example, but you can close streams or DB connections this way.
}
}
sb.setLength(0)
吗?
sb = null;
的 finally 块只是添加了不需要的代码。我理解您的意思是 finally
块是释放数据库连接等资源的好地方,但请记住,您的示例可能会使新手感到困惑。
System.out.println("---AGAIN2---");
System.out.println(sb);
行,现在更清楚了。事实上,输出与您的论文不符:p 我也添加到您的答案中,但编辑必须由主持人或类似的人接受。否则你可以添加它们
这实际上在任何语言中都是正确的……finally 总是在 return 语句之前执行,无论 return 在方法体中的什么位置。如果不是这样,finally 块就没有多大意义。
除了关于 return 在 try 块中最终替换 return 的点之外,异常也是如此。抛出异常的 finally 块将替换从 try 块中抛出的返回或异常。
不定期副业成功案例分享
thread.stop()
并不一定会阻止finally
块被执行。finally
块将在try
块之后 被调用,而before 控制权传递给以下语句。这与涉及无限循环的 try 块一致,因此 finally 块实际上从未被调用。