try-catch-finally中的4个巨坑,老程序员也搞不定!
坑1:finally中使用return
① 反例代码
public static void main(String[] args) throws FileNotFoundException {
System.out.println("执行结果:" + test());
}
private static int test() {
int num = 0;
try {
// num=1,此处不返回
num++;
return num;
} catch (Exception e) {
// do something
} finally {
// num=2,返回此值
num++;
return num;
}
}
② 原因分析
③ 解决方案
④ 正例代码
public static void main(String[] args) throws FileNotFoundException {
System.out.println("执行结果:" + testAmend());
}
private static int testAmend() {
int num = 0;
try {
num = 1;
} catch (Exception e) {
// do something
} finally {
// do something
}
// 确保 return 语句只在此处出现一次
return num;
}
坑2:finally中的代码“不执行”
① 反例代码
public static void main(String[] args) throws FileNotFoundException {
System.out.println("执行结果:" + getValue());
}
private static int getValue() {
int num = 1;
try {
return num;
} finally {
num++;
}
}
② 原因分析
// class version 52.0 (52)
// access flags 0x21
public class com/example/basic/FinallyExample {
// compiled from: FinallyExample.java
// access flags 0x1
public <init>()V
L0
LINENUMBER 5 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lcom/example/basic/FinallyExample; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x9
public static main([Ljava/lang/String;)V throws java/io/FileNotFoundException
L0
LINENUMBER 13 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "\u6267\u884c\u7ed3\u679c:"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKESTATIC com/example/basic/FinallyExample.getValue ()I
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
LINENUMBER 14 L1
RETURN
L2
LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
MAXSTACK = 3
MAXLOCALS = 1
// access flags 0xA
private static getValue()I
TRYCATCHBLOCK L0 L1 L2 null
L3
LINENUMBER 18 L3
ICONST_1
ISTORE 0
L0
LINENUMBER 20 L0
ILOAD 0
ISTORE 1
L1
LINENUMBER 22 L1
IINC 0 1
L4
LINENUMBER 20 L4
ILOAD 1
IRETURN
L2
LINENUMBER 22 L2
FRAME FULL [I] [java/lang/Throwable]
ASTORE 2
IINC 0 1
L5
LINENUMBER 23 L5
ALOAD 2
ATHROW
L6
LOCALVARIABLE num I L0 L6 0
MAXSTACK = 1
MAXLOCALS = 3
}
iconst 是将 int 类型的值压入操作数栈。istore 是将 int 存储到局部变量。iload 从局部变量加载 int 值。iinc 通过下标递增局部变量。ireturn 从操作数堆栈中返回 int 类型的值。astore 将引用存储到局部变量中。
0 iconst_1 在操作数栈中存储数值 1
1 istore_0 将操作数栈中的数据存储在局部变量的位置 0
2 iload_0 从局部变量读取值到操作数栈
3 istore_1 将操作数栈中存储 1 存储在局部变量的位置 1
4 iinc 0 by 1 把局部变量位置 0 的元素进行递增(+1)操作
7 iload_1 将局部位置 1 的值加载到操作数栈中
8 ireturn 返回操作数栈中的 int 值
③ 解决方案
④ 正例代码
private static int getValueByAmend() {
int num = 1;
try {
// do something
} catch (Exception e) {
// do something
} finally {
num++;
}
return num;
}
坑3:finally中的代码“非最后”执行
① 反例代码
public static void main(String[] args) throws FileNotFoundException {
execErr();
}
private static void execErr() {
try {
throw new RuntimeException();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
System.out.println("执行 finally.");
}
}
② 原因分析
public static void main(String[] args) {
System.out.println("我是标准输出流");
System.err.println("我是标准错误输出流");
}
“标准”错误输出流。该流已经打开,并准备接受输出数据。通常,此流对应于主机环境或用户指定的显示输出或另一个输出目标。按照惯例,即使主要输出流(out 输出流)已重定向到文件或其他目标位置,该输出流(err 输出流)也能用于显示错误消息或其他信息,这些信息应引起用户的立即注意。
public static void main(String[] args) throws FileNotFoundException {
// 将标准输出流的信息定位到 log.txt 中
System.setOut(new PrintStream(new FileOutputStream("log.txt")));
System.out.println("我是标准输出流");
System.err.println("我是标准错误输出流");
}
③ 解决方案
④ 正例代码
private static void execErr() {
try {
throw new RuntimeException();
} catch (RuntimeException e) {
System.out.println(e);
} finally {
System.out.println("执行 finally.");
}
}
坑4:finally中的代码“不执行”
在 try-catch 语句中执行了 System.exit;
在 try-catch 语句中出现了死循环;
在 finally 执行之前掉电或者 JVM 崩溃了。
① 反例代码
public static void main(String[] args) {
noFinally();
}
private static void noFinally() {
try {
System.out.println("我是 try~");
System.exit(0);
} catch (Exception e) {
// do something
} finally {
System.out.println("我是 fially~");
}
}
② 解决方案
总结
参考 & 鸣谢
评论