使用sonar检查代码时,出现了下面的问题
Jump statements should not occur in "finally" blocks
finally语句块中不能使用跳转语句——return/break/continue/throw/goto,其实与语法规则无关。也就是说,你要是非这么写,你的编译器不会爆出任何异常。但是它可能会产生一些出人意料的问题,我在网上搜到一些博客,都是比较早的,说的不是很准确,于是专门写一篇博客。本文参考:sona--Jump statements should not occur in "finally" blocks。sonar里写的很简明和清晰,但如果不想看英文,或者想看更详细的解释,就往下接着看吧。
“Jump statement”跳转语句,即我们标题中所说的return/break/continue/throw/goto。try…catch…finally的语句我们比较熟悉,finally是无论如何都要执行的,除非在try/catch的语句块中使用的“System.exit()”。大致如下。
try{
//有可能产生异常
}catch(Exception e){
//捕获产生的异常
}finally {
//无论是否异常,都要最终执行的语句
}
在finally中出现跳转语句,可能会导致两个问题(欢迎补充):
- try/catch/finally中同时出现不同跳转语句,以finally中为准。
- 阻止未处理的异常抛出。
首先来看第一个问题。如果try/catch的语句块有跳转语句,finally语句块先行。因为在执行的过程中,如果在try/catch中看到跳转语句,会将finally中的语句块前置,先执行,然后再去执行原try/catch中的跳转语句。这时,如果finally中的有跳转语句,则按照逻辑,就不会再去执行try/catch中的跳转语句了。示例代码:
public static void main(String[] args) {
try{
System.out.println(test());
}catch(Exception e){
System.out.println("Exception from main");
e.printStackTrace();
}finally {
System.out.println("finally from main");
}
}
public static boolean test() throws Exception{
try {
throw new Exception("Some error");
} catch (Exception e) {
System.out.println("Exception from test");
return true; //catch中的返回值无效
} finally {
System.out.println("finally word");
return false; //以finally的返回结果为准,返回false
}
}
执行后的结果如下:

“阻止未处理的异常抛出”。finally中的跳转语句会阻止异常的传递,也就是未经处理的异常,经过finally之后就会被吃掉。具体我们看下面的例子。和第一个例子比,去掉test()中的catch语句。这里我们很有可能会认为,异常会被test()抛出,再在主函数中被捕获,但实际上,异常经过test()的finally就被吃掉了。
public static void main(String[] args) {
try{
System.out.println(test());
}catch(Exception e){
System.out.println("Exception from main");
e.printStackTrace();
}finally {
System.out.println("finally from main");
}
}
public static boolean test() throws Exception{
try {
throw new Exception("Some error");
} finally {
System.out.println("finally word");
return false;
}
}
我们看一下输出结果,异常的传递被截断了,这样就导致一些未被捕获的异常不会发现,即使程序出现问题,也不容易发现和定位。注意,这里不是finally的问题,而是finally中的跳转语句导致的错误。

我们把跳转语句移出finally程序块,展示一下正确的使用,例子如下:
public static void main(String[] args) {
try{
System.out.println(test());
}catch(Exception e){
System.out.println("Exception from main");
e.printStackTrace();
}finally {
System.out.println("finally from main");
}
}
public static boolean test() throws Exception{
try {
throw new Exception("Some error");
}catch (IOException e){
System.out.println("Exception from test");
}finally {
System.out.println("finally word");
}
return false;
}
执行结果如下,异常可以正常捕获。


文章探讨了Java中finally语句块为何不应包含return/break/continue/throw/goto跳转语句。尽管语法上允许,但这样做可能导致意外行为,如改变执行流程或阻止未处理异常的抛出。作者通过示例代码说明,当finally块内有跳转语句时,可能覆盖try/catch中的跳转,导致异常处理丢失,不利于错误发现和定位。正确做法是将跳转语句移出finally块,确保异常能正常传播和处理。
67

被折叠的 条评论
为什么被折叠?



