多重返回语句没有编译器错误
这是一个采访问题:
public class Demo { public static void main(String[] args) { System.out.println(foo()); } static String foo() { try { return "try ..."; } catch (Exception e) { return "catch ..."; } finally { return "finally ..."; //got as result } } }
我的问题是为什么没有编译时错误。 当我在finally
块中有return语句的时候,它肯定会从finally
返回而不是try
和catch
块。 我试图用-Xlint
选项编译这段代码,它给出了一个警告。
warning: [finally] finally clause cannot complete normally
它没有给出编译错误,因为它是由Java语言规范所允许的。 但是,它提供了一个警告消息,因为在finally
块中包含return
语句通常是一个坏主意。
在你的例子中发生了以下事情。 try
块中的return
语句被执行。 但是, finally
块必须始终执行,以便在catch
块完成后执行。 在那里出现的return
语句覆盖了前面的return
语句的结果,所以方法返回第二个结果。
类似的, finally
块通常不应该抛出exception。 这就是为什么警告说finally
块应该正常完成,也就是没有return
或抛出exception。
这在Java语言规范中有描述:
§14.17
finally
一个子句的突然完成可能会中断由return
语句启动的控制权转移。
§14.20.2
如果
try
块的执行正常完成,则执行finally
块,然后有一个select:
- 如果
finally
块正常完成,则try
语句正常完成。- 如果
finally
块由于S原因突然完成,则try
语句由于原因S突然完成。如果
try
块的执行由于其他原因R突然完成,那么finally
块将被执行,然后有一个select:
- 如果
finally
块正常完成,那么由于原因R,try
语句突然完成。- 如果
finally
块由于S原因而突然完成,那么try
语句因为原因S突然完成(并且原因R被丢弃)。
没有编译时错误,因为只有1和1的return
语句实际上将控制返回到调用代码。
正如@Hoopje所述, try
或catch
return
将首先执行,它们各自的return语句也将执行。 但是在将控制权返回给调用代码之前,它将执行finally
块。 现在,这个block
也return
一些东西,所以这个返回覆盖了前一个。
它基本上与此相同:
public boolean someMethod(){ if(1 == 1){ return true; } return false; }
它不会给出编译错误,虽然它会给出警告。 编译器只会在没有执行return语句的机会时发生错误。
辉煌的问题..根据我的知识try和catch块的返回语句被转移到最后,如果你已经添加了最后阻止你的代码。 这就是它的工作。
所以在这种情况下,所有的代码行正在执行,你可以尝试debugging。 我在代码下面的所有三个块。
public class Main { public static void main(String[] args) { System.out.println(foo()); } static String foo() { try { throw new Exception(); } catch (Exception e) { return "catch ..."; } finally { return "finally ..."; //got as result } } }
你可以从下面的链接得到的想法。 多个回报:哪一个设置最终的回报值?
你的代码工作正常,因为在try,catch和finally块中只有一个返回语句。 如果您尝试在try,catch或finally块之一中写入两个return语句,表示存在无法访问的return语句,则会发生编译错误。
(简要回答 – 请阅读答案的粗体和斜体部分 )
执行stream程按照Java 8文档。 它为您提供了详细信息。 您可以根据以下内容推断返回语句的执行情况。
带有finally块的try语句通过首先执行try块来执行。
那么有一个select:
•如果try块的执行正常完成,则执行finally块,然后有一个select:
– 如果finally块正常完成,则try语句正常完成。
– 如果由于S原因finally块突然完成,则由于原因S,try语句突然完成。
•如果try块的执行由于抛出一个值V而突然完成,那么有一个select:
– 如果V的运行时types与try语句的任何catch子句的可捕获的exception类兼容,则select第一个(最左边的)这样的catch子句。 值V被分配给所选的catch子句的参数,并且该catch子句的Block被执行。
那么有一个select:
>如果catch块正常完成,则执行finally块。 那么有一个select:
如果finally块正常完成,则try语句正常结束。
»如果finally块由于某种原因突然完成,则try语句由于同样的原因突然完成。
> 如果由于原因R catch块突然完成,则执行finally块。 那么有一个select:
»如果finally块正常完成,那么try语句突然完成,原因是R.
» 如果finally块由于S原因而突然完成,那么try语句为S原因突然完成(并且原因R被丢弃)。
– 如果V的运行时types与try语句的任何catch子句的可捕获的exception类不是兼容的,则执行finally块。
那么有一个select:
>如果finally块正常完成,则try语句突然完成,因为抛出了值V.
>如果finally块由于S原因而突然完成,那么try语句为S原因突然完成(并丢弃和遗忘值V的抛出)。
•如果try块的执行由于其他原因R而突然完成,则执行finally块,然后有一个select:
– 如果finally块正常完成,则由于原因R,try语句突然完成。
– 如果finally块由于S原因而突然完成,那么try语句因为原因S突然完成(并且原因R被丢弃)。
解释在这个链接javaDoc清楚
尝试运行这个:
它会打印:1,2,3,然后通过零exception抛出一个除法
public class Demo { public static void main(String[] args) { System.out.println(foo()); } public static String print(int a){ System.out.println(a); return String.valueOf(a/0); } static String foo() { try { return print(1); } catch (Exception e) { return print(2); } finally { return print(3); } } }