参考文章:深入理解java异常处理机制
假设前提背景有:
int i = 0;
String greetings[] = { " Hello world !", " Hello World !! ", " HELLO WORLD !!!" };
1、因 try-catch 造成的死循环
(1)
while (i < 4) {
try {
System.out.println(greetings[i]);
i++;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界异常 " + i);
} finally {
System.out.println("--------------------------");
}
}
对于上述逻辑,是为造成死循环的。打印结果如下:
程序会在之后一直(循环)打印:
数组下标越界异常 3
--------------------------
陷入死循环的原因:
因为当 i == 2
时,执行完 i++
,此时 i == 3
,然后 greetings[i]
会造成数组越界异常,此时会被 catch 掉,因此不会再执行到 i++
(即 i 不会为 4),接下来执行了 finally 就会进入下一次循环(因为 i 为 3 小于 4),而执行到 greetings[i]
又出现异常,又不会执行 i++
,从而陷入死循环。
(2)
而如果将:
System.out.println(greetings[i]);
i++;
改成
greetings[i++]
即把两句合为一句,则不会出现死循环。
因为此时会执行完 i++
(使 i 达到 4) 再被 catch,因此会不满足 while 条件而退出循环。打印结果如下:
(3)
或者,将 try-catch 语句放在最外层。
try {
while (i < 4) {
System.out.println(greetings[i]);
i++;
}
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界异常 " + i);
return;
} finally {
System.out.println("--------------------------");
}
不会出现死循环,因为当 i == 3 时,会因异常退出整个 while 循环。打印结果如下:
此时,如果也将那两句合并为 System.out.println(greetings[i++])
,则打印结果为 4。
2、return 与 finally
首先需要明确的是,不管有没有发生异常,如果有 finally 语句,则 finally 都会执行。
除非是图中说明的那几种特殊情况:
public static int testException() {
int i = 0;
String[] greetings = {" Hello world !", " Hello World !! ",
" HELLO WORLD !!!"};
try {
while (i < 4) {
System.out.println(greetings[i]);
i++;
}
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界异常 " + i);
return 20;
} finally {
// 无论怎么样, finally 都将会执行
System.out.println("--------------------------");
}
// 此时 “return 30” 放在 try-catch-finally 的外面
return 30;
}
public static void main(String[] args) {
System.out.println(testException());
}
运行结果:
可以看到,在发生异常的前提下,即使在 catch 中 return 了(但是此时 return 30
放在 try-catch-finally 的外面),但是还是会执行 finally 中的逻辑,只不过此时 testException()
方法是 return 的结果是 catch 中的 20。
但是如果是这样,将 return 30
移到 finally 中:
public static int testException() {
...
} finally {
// 无论怎么样, finally 都将会执行
System.out.println("--------------------------");
return 30;
}
}
则此时 testException()
方法是 return 的结果是 finally 中的 30。
前面说的是发生异常的前提下,而不管有没有发生异常,如果 finally 中有 return 语句,则之后的逻辑都不会被执行了。如图,可以看到,编译器发出了警告: