【问题标题】:Does Java recognize infinite loops?Java 能识别无限循环吗?
【发布时间】:2010-12-29 20:04:39
【问题描述】:

给出以下代码示例:

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 规范中的某个地方,是否存在这种行为可能有用的情况?

【问题讨论】:

  • 难道你不需要在while(true); 之后加上return 0;(或等效的),只是为了让编译器满意吗?我知道我曾经抱怨过 Java 方法之前没有返回正确的类型。 ...话虽如此,我完全可以看到这是一个编译程序。
  • 非常有趣...我很惊讶它居然编译了。

标签: java loops while-loop


【解决方案1】:

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

至于您的问题:“当循环无限时,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();    
  }
}

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

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);不会被编译器忽略为不可访问,否则会抛出编译时错误!

【讨论】:

  • 您的回答具有误导性。计算机程序不可能识别任意程序是否停止,但检查“特定程序”是否停止绝对不是不可能的。毫无疑问,编译器可以检查没有breakgoto 语句的while (true); 是一个无限循环这一事实。
  • 布尔测试=真; while(test){ } 不一定是无限循环。另一个线程可以更改“测试”的值。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    重读问题后……

    Java 理解 while(true);永远无法真正完成,它不会完全跟踪以下代码。

    boolean moo = true;
    while (moo);
    

    这有用吗?值得怀疑。

    【讨论】:

    • 那“实际上在做什么”?
    • 这不一定是无限循环。另一个线程可以将 'moo' 设置为 false。
    【解决方案4】:

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

    【讨论】:

    • 但是,它确实可以编译。另外:while(true){ //code } 也可以编译,但不返回该 int!
    • while(true) 并非不可访问(显然!)。 while(true) 后面的任何语句都无法访问。
    • windfinder: while(true); 编译得很好,但 while (true); return 0; 不会。
    • 编译不返回的事实很奇怪!
    • @fastcodejava:实际上,如果循环之后的语句不被认为是不可访问的(例如,如果它是bool x = true; while(x);),编译器会考虑退出循环一个可能的“代码路径”并且需要你在那里写一个return 声明。否则,它不会编译没有 return.
    【解决方案5】:

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

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

    在某些情况下这种行为可能有用吗?

    我不这么认为,除非是在晦涩难懂的单元测试中。

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

    【讨论】:

      【解决方案6】:

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

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

      【讨论】:

        【解决方案7】:

        我只引用Java Language Specification,因为这很清楚:

        本节专门对“可达”一词进行精确解释。这个想法是,从包含语句的构造函数、方法、实例初始化器或静态初始化器的开头到语句本身必须有一些可能的执行路径。该分析考虑了语句的结构。除了特殊处理while、do和条件表达式为真值的语句外,流分析中不考虑表达式的值。

        ...

        如果以下至少一项为真,则 while 语句可以正常完成:

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

        ...

        如果 S 之前的语句可以正常完成,则非空块中不是 switch 块的所有其他语句 S 都是可访问的。

        然后将上述定义应用到this

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

        换句话说,具有返回类型的方法必须仅通过使用提供值返回的return语句才能返回;不允许“掉头”。

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

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

        【讨论】:

          【解决方案8】:

          关于不可达语句的一些注意事项:

          java2 specs 中可以找到“无法访问的语句”的描述。下面这句话特别有意思:

          除了条件表达式为真值的whiledofor语句的特殊处理外,流分析中不考虑表达式的值

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

          【讨论】:

            猜你喜欢
            • 2015-08-29
            • 1970-01-01
            • 1970-01-01
            • 2011-02-24
            • 2016-05-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多