Java是否识别无限循环?

时间:2009-12-24 14:45:41

标签: java loops while-loop

给出以下代码示例:

public class WeirdStuff {

    public static int doSomething() {
        while(true);
    }

    public static void main(String[] args) {
        doSomething();
    }
}

这是一个有效的Java程序,虽然方法doSomething()应该返回一个int但从来没有。如果你运行它,它将以无限循环结束。如果将while循环的参数放在一个单独的变量中(例如boolean bool = true),编译器会告诉你在这个方法中返回一个int。

所以我的问题是:这是Java规范中的某个地方,是否存在这种行为可能有用的情况?

8 个答案:

答案 0 :(得分:19)

我会引用Java Language Specification,因为它很清楚:

  

本节致力于对“可达”一词的精确解释。我们的想法是,从构造函数,方法,实例初始化程序或包含语句本身的静态初始化程序开始,必须有一些可能的执行路径。分析考虑了陈述的结构。除了对while,do和for条件表达式具有常量值的语句的特殊处理外,在流分析中不考虑表达式的值。

...

  

如果至少满足下列条件之一,则while语句可以正常完成:

     
      
  • 可以访问while语句,条件表达式不是值为true的常量表达式。
  •   
  • 有一个可到达的break语句退出while语句。
  •   

...

  

如果S之前的语句可以正常完成,则可以访问非交换块的非空块中的每个其他语句S.

然后将上述定义应用于this

  

如果声明方法具有返回类型,则其主体中的每个return语句(第14.17节)都必须具有Expression。如果方法的主体可以正常完成,则会发生编译时错误(第14.1节)。

     

换句话说,具有返回类型的方法必须仅使用提供值返回的return语句返回;它不允许“从它的身体末端掉下来。”

     

请注意,方法可能具有声明的返回类型,但不包含return语句。这是一个例子:

class DizzyDean {
  int pitch() { throw new RuntimeException("90 mph?!"); }
}

答案 1 :(得分:13)

Java规范定义了一个名为Unreachable statements的概念。您不允许在代码中包含无法访问的语句(这是编译时错误)。 while(true);语句根据定义使以下语句无法访问。在Java中的return语句之后,甚至不允许使用while(true);语句。请注意,虽然Halting problem在通用情况下是不可判定的,但是无法到达语句的定义比仅停止更严格。它决定非常具体的案例,程序肯定不会停止。从理论上讲,编译器无法检测所有无限循环和无法访问的语句,但它必须检测规范中定义的特定情况。

答案 2 :(得分:7)

如果你问无限循环是否有用,答案是肯定的。在很多情况下你想要一些永远运行的东西,尽管循环通常会在某个时候终止。

关于你的问题:“当循环无限时,java可以被识别吗?”答案是计算机不可能有一个算法来确定程序是否会永远运行。阅读:Halting Problem

再多一点,你的问题也在问为什么doSomething()函数不会抱怨它没有返回int。

有趣的是,以下来源不会编译。

public class test {
  public static int doSomething() {                
   //while(true);
   boolean test=true;
   while(test){


   }
  }  
  public static void main(String[] args) {               
   doSomething();    
  }
}

这向我表明,正如停止问题的维基页面所暗示的那样,不可能有一个算法来确定每个问题是否会终止,但这并不意味着有人没有添加简单的案例:

while(true);

到java规范。我上面的例子有点复杂,所以Java不能把它记住为无限循环。确实,这是一个奇怪的边缘情况,但它只是为了使事情编译。也许有人会尝试其他组合。

编辑:不存在无法访问的代码问题。

import java.util.*;

public class test {
  public static int doSomething() {                
   //while(true);
   while(true){
    System.out.println("Hello"); 
   }
  }  
  public static void main(String[] args) {               
   doSomething();    
  }
}

以上作品,所以while(true);编译器不会被忽略为无法访问,否则会抛出编译时错误!

答案 3 :(得分:1)

是的,您可以在某些线程中看到这些“无限”循环,例如在某个端口侦听传入消息的服务器线程。

答案 4 :(得分:1)

  

所以我的问题是:这是Java规范中的某个地方

根据规范,该程序是合法的Java。 JLS(和Java编译器)认识到该方法无法返回,因此不需要return语句。实际上,如果在循环之后添加了return语句,Java编译器会给你一个编译错误,因为return语句是无法访问的代码。

  

是否存在此行为可能有用的情况?

我不这么认为,除了可能在模糊的单元测试中。

我偶尔会编写永远不会返回的方法(通常),但是将当前线程放入不间断的无限繁忙循环中很少有任何意义。

答案 5 :(得分:0)

重读问题后....

Java了解(true);实际上永远无法完成,它不会完全跟踪以下代码。

boolean moo = true;
while (moo);

这有用吗?值得怀疑的。

答案 6 :(得分:0)

您可能正在实现一个通用接口,即使该方法可能以有意义的返回值退出,您的特定实现是一个有用的无限循环(例如,网络服务器),它永远不会有一种情况应该退出,即触发返回值的任何行动。

此外,对于像boolean x = true; while (x);这样的代码,此final上给定x修饰符进行编译。我不知道随便但是我想这是Java选择合理的直接常量表达式分析(需要直接定义,因为由于拒绝依赖于它的程序,它是语言定义的一部分)。

答案 7 :(得分:0)

关于无法达到的陈述的一些注释:

java2 specs中,可以找到“无法访问的陈述”的描述。特别有趣的是以下句子:

  

的特殊处理,执行 语句表达式具有常量值true的语句,流分析中不考虑表达式的值

因此,显然不可能退出while (true);无限循环。但是,还有两个选项:change cached values或直接攻击类文件或JVM操作内存空间。