Java中的无限循环
查看Java中的无限Java中的无限循环,java,halting-problem,Java,Halting Problem,查看Java中的无限while循环。它会导致下面的语句出现编译时错误 while(true) { System.out.println("inside while"); } System.out.println("while terminated"); //Unreachable statement - compiler-error. 但是,以下相同的无限while循环工作正常,不会出现任何错误,我只是用布尔变量替换了条件 boolean b=true; while(b) {
while
循环。它会导致下面的语句出现编译时错误
while(true) {
System.out.println("inside while");
}
System.out.println("while terminated"); //Unreachable statement - compiler-error.
但是,以下相同的无限
while
循环工作正常,不会出现任何错误,我只是用布尔变量替换了条件
boolean b=true;
while(b) {
System.out.println("inside while");
}
System.out.println("while terminated"); //No error here.
同样,在第二种情况下,循环后的语句显然是不可访问的,因为布尔变量
b
为true,但编译器根本不会抱怨。为什么?
Edit:以下版本的
while
明显陷入无限循环,但不会对其下的语句发出编译器错误,即使循环中的if
条件始终为false
,因此,循环永远不会返回,并且可以由编译器在编译时自行确定
while(true) {
if(false) {
break;
}
System.out.println("inside while");
}
System.out.println("while terminated"); //No error here.
编辑:与
if
和while
相同
if(false) {
System.out.println("inside if"); //No error here.
}
以下版本的
while
也陷入无限循环
while(true) {
try {
System.out.println("inside while");
return; //Replacing return with break makes no difference here.
} finally {
continue;
}
}
这是因为
finally
块始终被执行,即使return
语句在try
块本身中遇到它之前。编译器不够复杂,无法运行b
可能包含的值(尽管只分配一次)。第一个例子很容易让编译器看到,它将是一个无限循环,因为条件不是变量。因为分析变量状态很困难,所以编译器基本上放弃了,让你做你想做的事。此外,Java语言规范有明确的规则
boolean b=true;
while(b) {
System.out.println("inside while");
}
System.out.println("while terminated"); //No error here.
有很多方法可以欺骗编译器-另一个常见的例子是
public void test()
{
return;
System.out.println("Hello");
}
这是行不通的,因为编译器会意识到该区域是不可读取的。相反,你可以这样做
public void test()
{
if (2 > 1) return;
System.out.println("Hello");
}
这将起作用,因为编译器无法意识到表达式永远不会为false。后者不是不可访问的。
布尔b仍然有可能在循环中的某个地方被更改为false,从而导致结束条件。我很惊讶您的编译器拒绝编译第一个案例。我觉得这很奇怪
但是第二种情况没有优化到第一种情况,因为(a)另一个线程可能会更新
b
(b)被调用函数可能会修改b
的值作为副作用。编译器可以轻松明确地证明第一个表达式总是导致无限循环,但对第二个来说并不容易。在您的玩具示例中,它很简单,但如果:
- 变量的内容是从文件中读取的吗李>
- 该变量不是本地变量,可以由其他线程修改
- 变量依赖于某些用户输入
final
时,我的编译器确实会抱怨)我猜变量“b”有可能改变它的值,所以编译器认为System.out.println(“终止时”)代码>
可以达到。因为true是常量,而b可以在循环中更改。从编译器的角度来看,中的b
,而(b)
可能在某个地方更改为false。编译器只是不费心检查
为了好玩,请尝试而(1<2)
,则用于(int i=0;i<1;i--)
等。如果编译器能够最终确定布尔值在运行时将计算为true
,它将抛出该错误。编译器假定您声明的变量可以更改(尽管我们在这里知道它不会更改)
为了强调这一事实,如果变量在Java中声明为final
,大多数编译器将抛出与替换值相同的错误。这是因为变量是在编译时定义的(在运行时不能更改),因此编译器可以最终确定表达式在运行时的计算结果为true
。编译器不是完美的,也不应该是完美的
编译器的职责是确认语法,而不是确认执行。编译器最终可以捕获并防止强类型语言中的许多运行时问题,但它们无法捕获所有此类错误
实际的解决方案是使用一组单元测试来补充编译器的检查,或者使用面向对象的组件来实现已知健壮的逻辑,而不是依赖于原始变量和停止条件
强类型和OO:提高编译器的效率
有些错误本质上是语法性的——在Java中,强类型化使得许多运行时异常可以捕获。但是,通过使用更好的类型,您可以帮助编译器执行更好的逻辑
如果您希望编译器在Java中更有效地实施逻辑,那么解决方案是构建能够实施此类逻辑的健壮、必需的对象,并使用这些对象来构建应用程序,而不是原语
一个典型的例子是迭代器模式的使用,与Java的foreach循环相结合。与简化的while循环相比,该构造不易受到您所说明的错误类型的影响 以下是关于while语句的说明
while语句通常可以在至少一个
事实如下:
- while语句是可访问的,并且条件表达式不是值为true的常量表达式
- 有一个可到达的break语句退出while语句\
因此,编译器只会说while语句后面的代码是
while(true) {
try {
System.out.println("inside while");
return; //Replacing return with break makes no difference here.
} finally {
continue;
}
}
public void test()
{
return;
System.out.println("Hello");
}
public void test()
{
if (2 > 1) return;
System.out.println("Hello");
}