没有编译器错误的多个 return 语句
Multiple return statements without compiler error
这是一道面试题:
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
绑定到 return 而不是 try
和 catch
块。我试图用 -Xlint
选项编译这段代码,它给出了警告 as.
warning: [finally] finally clause cannot complete normally
没有编译时错误,因为 return
语句中只有 1 条且恰好 1 条实际上 return 将控制权返回给调用代码。
正如@Hoopje 所解释的,try
或 catch
中的 return
将首先执行,它们各自的 return 语句也会执行。但就在 return 将控件返回到调用代码之前,它将执行 finally
块。现在,这个 block
也是 return
的东西,所以这个 return 覆盖了前一个。
您的代码工作正常,因为在 try、catch 和 finally 块中只有一个 return 语句。如果您尝试在 try、catch 或 finally 块中写入两个 return 语句,表示存在无法访问的 return 语句,则会发生编译错误。
绝妙的问题.. 据我所知 return 如果您在代码中添加了 finally 块,则 try 和 catch 块的语句将转移到 finally 。这就是它的工作原理。
所以在这种情况下,所有代码行都在执行,您可以尝试调试。我在下面的代码中尝试了所有三个块。
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
}
}
}
你可以从下面得到这个想法link。
Multiple returns: Which one sets the final return value?
本质上是这样的:
public boolean someMethod(){
if(1 == 1){
return true;
}
return false;
}
虽然会给出警告,但不会给出编译错误。编译器只会在有可能 no return 语句被执行时给出错误。
这在 Java 语言规范中有描述:
Abrupt completion of a finally
clause can disrupt the transfer of
control initiated by a return
statement.
If execution of the try
block completes normally, then the finally
block is executed, and then there is a choice:
- If the
finally
block completes normally, then the try
statement completes normally.
- If the
finally
block completes abruptly for reason S, then the try
statement completes abruptly for reason S.
If execution of the try
block completes abruptly for any other reason
R, then the finally
block is executed, and then there is a choice:
- If the
finally
block completes normally, then the try
statement completes abruptly for reason R.
- If the
finally
block completes abruptly for reason S, then the try
statement completes abruptly for reason S (and reason R is discarded).
它不会给出编译错误,因为它是 Java 语言规范所允许的。但是,它会给出警告消息,因为在 finally
块中包含 return
语句通常不是一个好主意。
您的示例中发生的情况如下。 try
块中的 return
语句被执行。但是,必须始终执行 finally
块,因此它会在 catch
块完成后执行。那里出现的 return
语句覆盖了前一个 return
语句的结果,因此方法 returns 第二个结果。
类似地,finally
块通常不应抛出异常。这就是为什么警告说 finally
块应该正常完成,也就是说,没有 return
或抛出异常。
(简短回答-阅读答案的粗体和斜体部分)
根据 Java 8 文档的执行流程。它为您提供了详细信息。您可以根据以下内容推断 return 语句的执行。
带有 finally 块的 try 语句首先执行 try 块。
然后有一个选择:
• 如果 try 块的执行正常完成,则 finally 块是
执行,然后有一个选择:
– 如果 finally 块正常完成,则 try 语句完成
通常。
– 如果 finally 块由于原因 S 突然完成,则 try 语句
由于 S.
原因突然完成
• 如果 try 块的执行由于抛出值而突然完成
V,然后有一个选择:
– 如果 V 的 运行 时间类型与可捕获异常的赋值兼容
class try 语句的任何 catch 子句,然后是第一个(最左边)这样的子句
catch 子句被选中。值 V 被分配给参数
选择的 catch 子句,执行该 catch 子句的 Block。
然后有一个选择:
› 如果 catch 块正常完成,则执行 finally 块。
然后有一个选择:
» 如果 finally 块正常完成,则 try 语句
正常完成。
» 如果 finally 块由于任何原因突然完成,则 try
出于同样的原因,语句突然完成。
› 如果 catch 块由于原因 R 突然完成,则 finally 块
被执行。然后有一个选择:
» 如果 finally 块正常完成,则 try 语句
由于原因 R.
突然完成
» 如果 finally 块由于原因 S 突然完成,则 try
语句由于原因 S(并且原因 R 被丢弃)而突然完成。
– 如果 V 的 运行 时间类型与可捕获的赋值不兼容
try 语句的任何 catch 子句的异常 class,然后是 finally
块被执行。
然后有一个选择:
› 如果 finally 块正常完成,则 try 语句完成
突然因为抛出值 V.
› 如果 finally 块由于原因 S 突然完成,则 try 语句
由于 S 的原因突然完成(并且丢弃值 V 的抛出并且
忘记了)。
• 如果 try 块的执行由于任何其他原因 R 突然完成,则
finally块被执行,然后有一个选择:
– 如果 finally 块正常完成,则 try 语句完成
突然因为原因 R.
– 如果 finally 块由于原因 S 突然完成,则 try 语句
由于原因 S(并且丢弃原因 R)突然完成。
这个link- javaDoc
中的解释很清楚
尝试运行这个:
它将打印:1、2、3,然后抛出除以零的异常
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);
}
}
}
这是一道面试题:
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
绑定到 return 而不是 try
和 catch
块。我试图用 -Xlint
选项编译这段代码,它给出了警告 as.
warning: [finally] finally clause cannot complete normally
没有编译时错误,因为 return
语句中只有 1 条且恰好 1 条实际上 return 将控制权返回给调用代码。
正如@Hoopje 所解释的,try
或 catch
中的 return
将首先执行,它们各自的 return 语句也会执行。但就在 return 将控件返回到调用代码之前,它将执行 finally
块。现在,这个 block
也是 return
的东西,所以这个 return 覆盖了前一个。
您的代码工作正常,因为在 try、catch 和 finally 块中只有一个 return 语句。如果您尝试在 try、catch 或 finally 块中写入两个 return 语句,表示存在无法访问的 return 语句,则会发生编译错误。
绝妙的问题.. 据我所知 return 如果您在代码中添加了 finally 块,则 try 和 catch 块的语句将转移到 finally 。这就是它的工作原理。
所以在这种情况下,所有代码行都在执行,您可以尝试调试。我在下面的代码中尝试了所有三个块。
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
}
}
}
你可以从下面得到这个想法link。 Multiple returns: Which one sets the final return value?
本质上是这样的:
public boolean someMethod(){
if(1 == 1){
return true;
}
return false;
}
虽然会给出警告,但不会给出编译错误。编译器只会在有可能 no return 语句被执行时给出错误。
这在 Java 语言规范中有描述:
Abrupt completion of a
finally
clause can disrupt the transfer of control initiated by areturn
statement.
If execution of the
try
block completes normally, then thefinally
block is executed, and then there is a choice:
- If the
finally
block completes normally, then thetry
statement completes normally.- If the
finally
block completes abruptly for reason S, then thetry
statement completes abruptly for reason S.If execution of the
try
block completes abruptly for any other reason R, then thefinally
block is executed, and then there is a choice:
- If the
finally
block completes normally, then thetry
statement completes abruptly for reason R.- If the
finally
block completes abruptly for reason S, then thetry
statement completes abruptly for reason S (and reason R is discarded).
它不会给出编译错误,因为它是 Java 语言规范所允许的。但是,它会给出警告消息,因为在 finally
块中包含 return
语句通常不是一个好主意。
您的示例中发生的情况如下。 try
块中的 return
语句被执行。但是,必须始终执行 finally
块,因此它会在 catch
块完成后执行。那里出现的 return
语句覆盖了前一个 return
语句的结果,因此方法 returns 第二个结果。
类似地,finally
块通常不应抛出异常。这就是为什么警告说 finally
块应该正常完成,也就是说,没有 return
或抛出异常。
(简短回答-阅读答案的粗体和斜体部分)
根据 Java 8 文档的执行流程。它为您提供了详细信息。您可以根据以下内容推断 return 语句的执行。
带有 finally 块的 try 语句首先执行 try 块。
然后有一个选择:
• 如果 try 块的执行正常完成,则 finally 块是 执行,然后有一个选择:
– 如果 finally 块正常完成,则 try 语句完成 通常。
– 如果 finally 块由于原因 S 突然完成,则 try 语句 由于 S.
原因突然完成• 如果 try 块的执行由于抛出值而突然完成 V,然后有一个选择:
– 如果 V 的 运行 时间类型与可捕获异常的赋值兼容 class try 语句的任何 catch 子句,然后是第一个(最左边)这样的子句 catch 子句被选中。值 V 被分配给参数 选择的 catch 子句,执行该 catch 子句的 Block。
然后有一个选择:
› 如果 catch 块正常完成,则执行 finally 块。 然后有一个选择:
» 如果 finally 块正常完成,则 try 语句 正常完成。
» 如果 finally 块由于任何原因突然完成,则 try 出于同样的原因,语句突然完成。
› 如果 catch 块由于原因 R 突然完成,则 finally 块 被执行。然后有一个选择:
» 如果 finally 块正常完成,则 try 语句 由于原因 R.
突然完成» 如果 finally 块由于原因 S 突然完成,则 try 语句由于原因 S(并且原因 R 被丢弃)而突然完成。
– 如果 V 的 运行 时间类型与可捕获的赋值不兼容 try 语句的任何 catch 子句的异常 class,然后是 finally 块被执行。
然后有一个选择:
› 如果 finally 块正常完成,则 try 语句完成 突然因为抛出值 V.
› 如果 finally 块由于原因 S 突然完成,则 try 语句 由于 S 的原因突然完成(并且丢弃值 V 的抛出并且 忘记了)。
• 如果 try 块的执行由于任何其他原因 R 突然完成,则 finally块被执行,然后有一个选择:
– 如果 finally 块正常完成,则 try 语句完成 突然因为原因 R.
– 如果 finally 块由于原因 S 突然完成,则 try 语句 由于原因 S(并且丢弃原因 R)突然完成。
这个link- javaDoc
中的解释很清楚尝试运行这个:
它将打印:1、2、3,然后抛出除以零的异常
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);
}
}
}