try-catch-finally 简介¶
在 Java 中,try-catch-finally
语句可用于错误捕获和错误处理。程序员将可能会抛出异常的代码置于 try
块中,使用 catch
来捕获不同类型的错误,并在 catch
块中编写错误处理代码。最后可以使用 finally
块来清理相关资源。
若 try
块内的代码抛出异常,就可能被 catch
捕获到,最后运行 finally
;而若 try
中代码不抛出异常,最后也应该运行 finally
块中的代码。
但是在一些特殊情况下,try-catch-finally
代码的顺序变得难以确定。此文为这些可能的特殊情况做了一个简单的整理与总结。
异常情况总结¶
try 中含有 return¶
try 中产生异常¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class withReturn {
public static void main(String[] args) {
System.out.println(catchException());
}
private static void throwException() throws Exception {
throw new Exception("throwing Exception");
}
private static String catchException() {
try {
System.out.println("try block");
throwException();
return "try return";
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
} finally {
System.out.println("finally block");
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
4
| try block
catch the exception: `java.lang.Exception: throwing Exception` in catch block
finally block
outside the try-catch-finally block
|
可见,运行顺序遵循 try -> catch -> finally
,在抛出异常后,会直接运行到 catch
中的语句,而不会运行 try
中的 return
语句。这与我们的预期一致。
try 中不产生异常¶
即:能够运行到 try
中的 return
语句。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| public class withReturn {
public static void main(String[] args) {
System.out.println(noException());
}
private static String noException() {
try {
System.out.println("try block");
return "try return";
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
} finally {
System.out.println("finally block");
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
| try block
finally block
try return
|
可见,当 try
中没有异常抛出时,在 try
中的 return
语句被执行时会运行 finally
中的代码,再返回 try
中 return
语句的返回值。
try, catch, finally 中都有 return¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| public class withReturn {
public static void main(String[] args) {
System.out.println(allReturn());
}
private static String allReturn() {
try {
System.out.println("try block");
return "try return";
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
return "catch return";
} finally {
System.out.println("finally block");
return "finally return";
}
}
}
|
运行结果为:
1
2
3
| try block
finally block
finally return
|
若 finally
中有 return
语句,则会直接从 finally
中返回结果,try
块中的 return
结果则被丢弃。
catch, finally 抛出异常¶
catch 抛出异常¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| public class catchFinallyException {
public static void main(String[] args) {
System.out.println(catchThrowException());
}
private static void throwException() throws Exception {
throw new Exception("throwing Exception");
}
private static String catchThrowException() {
try {
System.out.println("try block");
throwException();
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
int a = 2 / 0; // ArithmeticException
System.out.println("catch end");
} finally {
System.out.println("finally block");
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
4
5
6
7
| try block
catch the exception: `java.lang.Exception: throwing Exception` in catch block
finally block
Exception in thread "main" java.lang.ArithmeticException: / by zero
at tryCatchFinally.catchFinallyException.catchThrowException(catchFinallyException.java:18)
at tryCatchFinally.catchFinallyException.main(catchFinallyException.java:5)
|
可见,catch
块在抛出异常后终止,最后 main
线程会抛出异常,但是 finally
块仍然运行。
finally 抛出异常¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| public class catchFinallyException {
public static void main(String[] args) {
System.out.println(catchFinallyException());
}
private static void throwException() throws Exception {
throw new Exception("throwing Exception");
}
private static String catchFinallyException() {
try {
System.out.println("try block");
throwException();
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
} finally {
System.out.println("finally block");
int a = 2 / 0; // ArithmeticException
System.out.println("finally end");
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
4
5
6
7
| try block
catch the exception: `java.lang.Exception: throwing Exception` in catch block
finally block
Exception in thread "main" java.lang.ArithmeticException: / by zero
at tryCatchFinally.catchFinallyException.catchFinallyException(catchFinallyException.java:20)
at tryCatchFinally.catchFinallyException.main(catchFinallyException.java:5)
|
可见,finally
块运行到抛出异常后终止,最后 main
线程也会抛出异常。
try, catch, finally 中有 continue¶
try 中有 continue¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| public class withContinue {
public static void main(String[] args) {
System.out.println(tryContinue());
}
private static String tryContinue() {
for (int i = 0; i < 2; i++) {
try {
System.out.println("try block");
continue;
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
} finally {
System.out.println("finally block");
}
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
4
5
| try block
finally block
try block
finally block
outside the try-catch-finally block
|
当代码运行到 try
的 continue
后,执行 finally
块中的逻辑再继续循环。
catch 中有 continue¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| public class withContinue {
public static void main(String[] args) {
System.out.println(catchContinue());
}
private static String catchContinue() {
for (int i = 0; i < 2; i++) {
try {
System.out.println("try block");
throw new Exception("throwing exception");
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
continue;
} finally {
System.out.println("finally block");
}
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
4
5
6
7
| try block
catch the exception: `java.lang.Exception: throwing exception` in catch block
finally block
try block
catch the exception: `java.lang.Exception: throwing exception` in catch block
finally block
outside the try-catch-finally block
|
可见,仍然会继续运行 finally
块中的代码再进行下次循环。
finally 中有 continue¶
在 catch
块中抛出异常,观察 finally
中 continue
的运行现象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| public class withContinue {
public static void main(String[] args) throws Exception {
System.out.println(finallyContinue());
}
private static String finallyContinue() throws Exception {
for (int i = 0; i < 2; i++) {
try {
System.out.println("try block");
throw new Exception("throwing exception");
} catch (Exception e) {
System.out.println("catch block, throwing exception");
throw new Exception("throwing exception");
} finally {
System.out.println("finally block");
continue;
}
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
4
5
6
7
| try block
catch block, throwing exception
finally block
try block
catch block, throwing exception
finally block
outside the try-catch-finally block
|
主线程并不会捕获到异常,因为 finally
中的 continue
导致 catch
中的异常无法被抛出。
try, catch, finally 中有 break¶
try 中有 break¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public class withBreak {
public static void main(String[] args) throws Exception {
System.out.println(tryBreak());
}
private static String tryBreak() {
for (int i = 0; i < 2; i++) {
try {
System.out.println("try block");
break;
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
} finally {
System.out.println("finally block");
}
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
| try block
finally block
outside the try-catch-finally block
|
当代码运行到 try
的 break
后,执行 finally
块中的逻辑跳出循环。
catch 中有 break¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| public class withBreak {
public static void main(String[] args) throws Exception {
System.out.println(catchBreak());
}
private static String catchBreak() {
for (int i = 0; i < 2; i++) {
try {
System.out.println("try block");
throw new Exception("throwing exception");
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
break;
} finally {
System.out.println("finally block");
}
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
4
| try block
catch the exception: `java.lang.Exception: throwing exception` in catch block
finally block
outside the try-catch-finally block
|
在 catch
中捕获异常后仍然会继续运行 finally
块中的代码再跳出循环。
finally 中有 break¶
在 catch
块中抛出异常,观察 finally
中 break
的运行现象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| public class withBreak {
public static void main(String[] args) throws Exception {
System.out.println(tryBreak());
}
private static String finallyBreak() throws Exception {
for (int i = 0; i < 2; i++) {
try {
System.out.println("try block");
throw new Exception("throwing exception");
} catch (Exception e) {
System.out.println("catch block, throwing exception");
throw new Exception("throwing exception");
} finally {
System.out.println("finally block");
break;
}
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
3
4
| try block
catch block, throwing exception
finally block
outside the try-catch-finally block
|
与 finally 中有 continue 的结果类似。主线程并不会捕获到异常,因为 finally
中的 break
导致 catch
中的异常无法被抛出。
try, catch 中有 exit¶
当 try
,catch
中有 System.exit()
时,JVM 将被关闭,finally 中的代码将不会被运行。
try 中有 exit¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| public class withExit {
public static void main(String[] args) {
System.out.println(tryExit());
}
private static String tryExit() {
try {
System.out.println("try block");
System.exit(1);
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
} finally {
System.out.println("finally block");
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
可见,程序直接从 try
块中的 System.exit(1)
退出了,没有执行 finally
块的内容。
catch 中有 exit¶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class withExit {
public static void main(String[] args) {
System.out.println(catchExit());
}
private static void throwException() throws Exception {
throw new Exception("throwing Exception");
}
private static String catchExit() {
try {
System.out.println("try block");
throwException();
} catch (Exception e) {
System.out.printf("catch the exception: `%s` in catch block\n", e.toString());
System.exit(1);
} finally {
System.out.println("finally block");
}
return "outside the try-catch-finally block";
}
}
|
运行结果为:
1
2
| try block
catch the exception: `java.lang.Exception: throwing Exception` in catch block
|
程序直接从 catch
块中的 System.exit(1)
退出了,没有执行 finally
块的内容。
守护进程¶
当程序中所有用户线程都终止时,JVM 会终止所有相关守护线程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class withThread {
public static void main(String[] args) {
System.out.println(daemonThread());
}
private static String daemonThread() {
Thread thread = new Thread(() -> {
try {
System.out.println("try block");
Thread.sleep(2000);
System.out.println("try end");
} catch (InterruptedException e) {
System.out.println("catch block");
} finally {
System.out.println("finally block");
}
});
thread.setDaemon(true);
thread.start();
return "main thread end";
}
}
|
新建一个守护线程,并在其 try 块中设置一个执行时间很久的任务(这里用 sleep 代替)。主线程将守护进程启动后,即可退出。
运行结果为:
1
2
| main thread end
try block
|
可见其在主线程退出后,守护线程也被终止了。而且值得注意的是,守护线程并没有执行 finally
块,而是直接被 JVM 终止(就如运行 System.exit()
)。
本作品采用
知识共享署名-相同方式共享 4.0 国际许可协议进行许可。