java-while(true);循环在不处于空状态时抛出无法访问的代码
我在用java编写一些小程序。我知道如果我写while(true);
,程序将在这个循环中冻结。如果代码是这样的:
测试1:
public class While {
public static void main(String[] args) {
System.out.println("start");
while (true);
System.out.println("end");
}
}
编译器向我抛出错误:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Unreachable code
at While.main(While.java:6)
我不知道这个错误存在。但我知道为什么会被扔。当然,第6行无法访问,导致编译问题。然后我测试了这个:
测试2:
public class While {
public static void main(String[] args) {
System.out.println("start");
a();
b();
}
static void a() {
while(true);
}
static void b() {
System.out.println("end");
}
}
由于某种原因,程序正常运行(控制台打印“开始”,然后冻结)。编译器无法检查void a()
的内部,并且无法访问它。我确实试过:
测试3:
public class While {
public static void main(String[] args) {
System.out.println("start");
a();
System.out.println("end");
}
static void a() {
while(true);
}
}
与测试2的结果相同强>
经过一些研究,我发现了这一点因此,如果括号内的代码是一个变量,编译器不会抛出异常。这是有道理的,但我不认为这同样适用于voids
Q:那么,如果void b()
(测试2)和System.out.println("end");
(测试3)无法访问,为什么编译器在测试1时抛出错误
编辑:我用C++尝试了测试1:
#include <iostream>
using namespace std;
int main()
{
cout << "start" << endl;
while(true);
cout << "end" << endl;
return 0;
}
编译器没有抛出任何错误,然后我得到了与测试2和测试3相同的结果。所以我想这是java的东西
# 1 楼答案
答案在于Java Language Specification为可达性制定的规则。它首先指出
然后
及
在第一个示例中,有一个while循环无法正常完成,因为它有一个条件,该条件是一个值为
true
的常量表达式,并且其中没有可到达的break
在第二个和第三个示例中,expression statement(方法调用)是可访问的,因此可以正常完成
上面的规则是Java的规则。C++可能有自己的规则,其他语言也一样。p>
# 2 楼答案
Unreachable code是一个编译时错误,简单地说,“这个程序的流程没有意义;有些东西永远无法到达
很明显,由于无休止的循环,您的测试执行得很好,但是为什么第一个测试会因为编译时错误而失败呢
好的,但是关于方法调用(比如
a()
)呢?为什么测试2和3成功编译因为方法调用被认为是一个表达式,所以只要在它之前没有任何东西阻止它的逻辑执行路径,它们就始终是可访问的
为了更好地说明这种编译机制背后的一些原因,让我们以
if
语句为例以上内容在编译时是正确的(尽管许多IDE肯定会抱怨!)
The Java 1.7 Specification talks about this
此外,还有一个向后兼容的原因:
大多数(根据规范),如果不是全部的话,Java编译器的实现都会遍历到方法中。当解析Java代码本身时,它将
a()
视为MethodInvocationElement
,这意味着该代码调用其他代码。我真的不在乎,我只是看看语法。”从语法上讲,,在调用a()
之后,后续代码属于它是有意义的记住性能成本。编译已经花费了相当长的时间。为了保持速度,Java编译器实际上不会递归到方法中;这需要花费很长时间(理论上,编译器必须评估很多很多代码路径)
要进一步重申它在语法上是受驱动的,可以直接在^{中的循环之后添加
return;
语句。不会编译,是吗在语法上,但是,没有它是有意义的# 3 楼答案
总的来说,不可能绝对肯定地确定某物是否可以到达
为什么?它相当于Halting Problem
停顿的问题是:
这个问题已被证明是无法解决的
X段代码是否可访问,这与在代码停止之前说明代码是否可访问是一样的
因为这是一个无法解决的问题,编译器(用Java或任何其他语言)并不努力解决它。如果它碰巧确定确实无法访问,那么您将收到警告。如果没有,可能也可能无法访问
在Java中,无法访问的代码是编译器错误。因此,为了保持兼容性,语言规范精确地定义了编译器应该尝试的“努力程度”。(根据其他答案,这是“不要进入另一个函数”。)
在其他语言(如C++)中,编译器可能会进一步优化。(内联函数并发现它永远不会返回后,可能会检测到无法访问的代码。)
# 4 楼答案
编译器应将language spec has an exact definition视为不可访问代码,另请参见https://stackoverflow.com/a/20922409/14955
特别是,它不关心一个方法是否完成,也不查看其他方法的内部
它不会做更多的事情
然而,你可以使用FindBugs这样的静态代码分析工具来进行“更深入”的分析(不确定它们是否检测到了你描述的模式,不过,正如其他人所指出的,在所有通用性中,停顿问题无论如何都无法通过算法解决,因此必须在“最佳努力”的合理定义上划清界限)