1. 概述
在这个教程中,我们将讨论Java规范(Java规范,第14.22节)中的一项内容:编译器应该在遇到任何不可达语句时抛出错误。不可达语句是指程序执行过程中永远不会被执行的代码,因为程序流程无法到达它。我们将通过各种代码示例来说明这个定义。
2. 循环后的break
指令
在循环中,如果我们在break
语句后放置指令,这些指令是不可达的:
public class UnreachableStatement {
public static void main(String[] args) {
for (int i=0; i<10; i++) {
break;
int j = 0;
}
}
}
尝试用javac
编译我们的代码:
$ javac UnreachableStatement.java
UnreachableStatement.java:9: error: unreachable statement
int j = 0;
^
1 error
正如预期,编译失败,因为int j = 0;
语句不可达。类似地,循环中的continue
语句后的指令也是不可达的:
public static void main(String[] args) {
int i = 0;
while (i<5) {
i++;
continue;
int j = 0;
}
}
3. while(true)
后的代码
一个while(true)
语句意味着其内部代码会永远运行。因此,其后的任何代码都是不可达的:
public static void main(String[] args) {
while (true) {}
int j = 0;
}
再次,前一个代码中的int j = 0;
语句不可达。这个评论同样适用于使用do-while
结构的等效代码:
public static void main(String[] args) {
do {} while (true);
int j = 0;
}
另一方面,while(false)
循环内的任何代码都是不可达的:
public static void main(String[] args) {
while (false) {
int j = 0;
}
}
4. 方法返回后的代码
方法在return
语句后立即退出。因此,此语句之后的任何代码都是不可达的:
public static void main(String[] args) {
return;
int i = 0;
}
又一次,int j = 0;
行不可达,导致编译错误。同样,当throw
语句不被try-catch
块包围或在throws
子句中指定时,方法会以异常方式完成。因此,此行之后的任何代码都不可达:
public static void main(String[] args) throws Exception {
throw new Exception();
int i = 0;
}
总结来说,如果所有代码分支都返回,那么以下代码无论如何都无法到达:
public static void main(String[] args) throws Exception {
int i = new Random().nextInt(0, 10);
if (i > 5) {
return;
} else {
throw new Exception();
}
int j = 0;
}
在这个例子中,我们选择了一个随机数在0(包括)和10(不包括)之间。如果这个数字大于5,我们会立即返回;否则,我们抛出一个通用的Exception
。因此,if-else
块后的代码没有可能的执行路径。
5. 死但可达到的代码
最后,值得注意的是,即使明显的死代码也不一定从编译器的角度说是不可达的。特别是,它不会评估if
语句内的条件:
public static void main(String[] args) {
if (false) {
return;
}
}
即使一眼就能看出if
块内的代码是死代码,这段代码也能成功编译。
6. 总结
在这篇文章中,我们探讨了多种不可达语句的情况。开发者社区对是否应将不可达代码视为警告还是错误存在争议。Java语言遵循每行代码都应该有目的的原则,因此选择抛出错误。而在像C++这样的其他语言中,由于编译器可以执行尽管存在不一致性,它通常只会发出警告。