多重返回语句没有编译器错误

这是一个采访问题:

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返回而不是trycatch块。 我试图用-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所述, trycatch return将首先执行,它们各自的return语句也将执行。 但是在将控制权返回给调用代码之前,它将执行finally块。 现在,这个blockreturn一些东西,所以这个返回覆盖了前一个。

它基本上与此相同:

 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); } } }