Java中finally块是否总是会执行

Java中finally块是否总是会执行

技术背景

在Java编程里,try-catch-finally语句是处理异常的关键机制。finally块的设计初衷是确保无论try块里是否出现异常,某些代码都能得到执行,常用于资源清理等操作。然而,finally块并非在所有情况下都会执行。

实现步骤

通常情况下的执行

一般而言,finally块会在trycatch代码块执行完毕后执行。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
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");
}
}
}

此代码的输出为:

1
2
something is printed
0

不执行finally块的情况

  1. 调用System.exit()
1
2
3
4
5
6
7
8
9
public class Main {
public static void main(String[] args) {
try {
System.exit(0);
} finally {
System.out.println("This will not be printed.");
}
}
}
  1. 调用Runtime.getRuntime().halt(exitStatus):该方法会直接终止JVM,finally块不会执行。
  2. JVM崩溃:当JVM因硬件故障、操作系统问题等崩溃时,finally块无法执行。
  3. trycatch块中出现无限循环
1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void main(String[] args) {
try {
while (true) {
// Infinite loop
}
} finally {
System.out.println("This will not be printed.");
}
}
}
  1. 操作系统强制终止JVM进程:例如在UNIX系统中使用kill -9 <pid>命令。
  2. 主机系统故障:如电源故障、硬件错误、操作系统崩溃等。
  3. finally块由守护线程执行,且所有非守护线程在finally块执行前退出

finally块对返回值和异常的影响

  • 返回值覆盖:若finally块中有return语句,会覆盖trycatch块中的返回值。
1
2
3
4
5
6
7
public static int getMonthsInYear() {
try {
return 10;
} finally {
return 12;
}
}

此方法会返回12

  • 异常屏蔽:若finally块抛出异常,会屏蔽trycatch块中的异常。
1
2
3
4
5
6
7
public static int getMonthsInYear() {
try {
throw new RuntimeException();
} finally {
return 12;
}
}

该方法不会抛出异常,而是返回12

核心代码

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
27
28
29
30
31
public class FinallyExample {
public static int testReturn() {
try {
return 0;
} finally {
System.out.println("Finally block is executed.");
}
}

public static void testSystemExit() {
try {
System.exit(0);
} finally {
System.out.println("This will not be printed.");
}
}

public static int testReturnOverride() {
try {
return 10;
} finally {
return 12;
}
}

public static void main(String[] args) {
System.out.println(testReturn());
// testSystemExit();
System.out.println(testReturnOverride());
}
}

最佳实践

  • 资源清理:在finally块中进行资源清理操作,像关闭文件、数据库连接等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.io.FileInputStream;
import java.io.IOException;

public class ResourceCleanup {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
// Read file
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
  • 避免在finally块中返回值或抛出异常:这可能会导致代码逻辑混乱,掩盖trycatch块中的问题。

常见问题

为何在finally块中返回值会覆盖trycatch块中的返回值?

这是Java语言的规定,finally块的代码会在trycatch块的return语句执行前执行。若finally块中有return语句,就会覆盖之前的返回值。

如何保证资源在异常情况下也能正确释放?

使用try-with-resources语句,它会自动关闭实现了AutoCloseable接口的资源,避免手动在finally块中关闭资源的繁琐和可能出现的错误。

1
2
3
4
5
6
7
8
9
10
11
12
import java.io.FileInputStream;
import java.io.IOException;

public class TryWithResourcesExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("test.txt")) {
// Read file
} catch (IOException e) {
e.printStackTrace();
}
}
}

Java中finally块是否总是会执行
https://119291.xyz/posts/2025-04-22.java-finally-block-execution/
作者
ww
发布于
2025年4月23日
许可协议