当前位置: 首页 > 知识库问答 >
问题:

虽然(正确);循环在不处于空状态时抛出无法访问的代码

许自强
2023-03-14

我在用java编写一些小程序。我知道如果我写while(true) 程序将在此循环中冻结。如果代码是这样的:

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行无法访问,导致编译问题。然后我测试了这个:

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");
    }
}

由于某种原因,程序运行正常(控制台打印了“开始”,然后冻结了)。编译器无法检查uluala()的内部,并看到它是不可访问的。为了确保我尝试了:

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

问:那么,如果void b()(测试2)和系统,为什么编译器会在测试1中抛出错误呢。出来println(“结束”) (测试3)无法访问?

编辑:我试过C中的测试1:

#include <iostream>

using namespace std;

int main()
{
    cout << "start" << endl;
    while(true);
    cout << "end" << endl;
    return 0;
}

编译器没有抛出任何错误,然后我得到了与测试2和测试3相同的结果。所以我想这是java的事情?


共有3个答案

慕胡媚
2023-03-14

无法访问的代码是一个编译时错误,简单地说“这个程序的流程没有意义;永远不会到达的东西”。

很明显,由于无休止的循环,您的测试执行得很好,但是为什么第一个测试会因为编译时错误而失败呢?

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

>

  • 当语句是可达的,并且条件表达式不是一个值为true的常量表达式(§15.28)。

    有一个可到达的break语句退出while语句。

    好的,但是关于方法调用(比如a())呢?为什么测试2和3成功编译?

    • 如果表达式语句是可访问的,则可以正常完成。

    因为方法调用被认为是一个表达式,所以只要在它阻塞其逻辑执行路径之前没有任何东西,它们就始终是可访问的。

    为了更好地说明这种编译机制背后的一些原因,让我们以if语句为例。

    if(false)
       System.out.println("Hello!"); // Never executes
    

    以上内容在编译时是正确的(尽管许多IDE肯定会抱怨!)。

    Java1.7规范谈到了这一点:

    这种不同处理的基本原理是允许程序员定义“标志变量”,例如:

    static final boolean DEBUG = false;
    

    然后编写代码,例如:

    if (DEBUG) { x=3; }
    

    其思想是,应该可以将DEBUG的值从false更改为true或从true更改为false,然后正确编译代码,而不需要对程序文本进行其他更改。

    此外,实际上还有一个向后兼容的原因:

    这种“有条件地编译”的能力对二进制兼容性有重大影响,并与之相关(§13)。如果编译了一组使用这种“flag”变量的类,并且省略了条件代码,那么以后只分发包含该标志定义的类或接口的新版本是不够的。因此,对标志值的更改与预先存在的二进制文件不兼容(§13.4.9)。(这种不兼容还有其他原因,例如在switch语句的case标签中使用常量;参见§13.4.9。)

    大多数(根据规范),如果不是全部的话,Java编译器的实现不会遍历到方法中。当解析Java代码本身时,它将a()视为一个MethodInvocationElement,意思是“此代码调用其他代码”。我真的不在乎,我只是看看语法。”。从语法上讲,在调用a()之后,后续代码就应该属于它。

    记住性能成本。编译已经花费了相当多的时间。为了保持快速,Java编译器实际上并不递归到方法中;这将需要很长时间(理论上,编译器必须评估许多许多代码路径)。

    要进一步重申它是语法驱动的,可以直接在a()中的循环之后添加一个返回;语句。不编译,是吗?不过,从语法上来说,没有它是有意义的。

  • 东方辉
    2023-03-14

    一般来说,用绝对肯定来确定某样东西是否可到达是不可能的。

    为什么?这相当于停顿问题。

    停顿的问题是:

    给出一个任意计算机程序的描述,决定该程序是结束运行还是永远继续运行。

    这个问题已被证明是无法解决的。

    X段代码是否可访问,就等于说它之前的代码是否会停止。

    因为这是一个无法解决的问题,编译器(用Java或任何其他语言)并不努力解决它。如果它碰巧确定确实无法访问,那么您将收到警告。如果没有,可能也可能无法访问。

    在Java,无法访问的代码是编译器错误。所以为了保持兼容性,语言规范准确地定义了编译器应该尝试的“多努力”。(根据其他答案,是“不要进入另一个函数”。)

    在其他语言(如C)中,编译器可能会进一步进行优化。(内联函数并发现它永远不会返回后,可能会检测到无法访问的代码。)

    李安歌
    2023-03-14

    语言规范有一个确切的定义,编译器应该将其视为不可访问的代码,另请参见https://stackoverflow.com/a/20922409/14955.

    特别是,它不关心一个方法是否完成,也不查看其他方法的内部。

    它不会做更多。

    然而,您可以使用像FindBugs这样的静态代码分析工具来进行“更深层次”的分析(虽然也不确定它们是否检测到您所描述的模式,而且,正如其他人所指出的,无论如何,停止问题在所有方面都不能通过算法来解决,所以人们必须在“最大努力”的合理定义上划清界限)。

     类似资料:
    • 问题内容: 我在用Java做一些小程序。我知道,如果我编写 程序,程序将在此循环中冻结。如果代码是这样的: 测试1: 编译器抛出错误: 我不知道这个错误存在。但是我知道为什么会抛出它。当然, 第6行无法访问 ,从而导致编译问题。然后,我对此进行了测试: 测试2: 由于某种原因 ,程序正常运行 (控制台先打印“开始”,然后冻结)。编译器无法检查内部, 并无法访问。确保我尝试过: 测试3: 与测试2相

    • 我试图创建一个函数,使用不同的字段作为权重将数据分成十分之一,这样我就可以有相等的暴露桶。在这样做的时候,我创建了一个简单的例子,我试图进入3个桶。我确实在第一部分遇到了困难,那就是让这个while循环工作起来: 我的成绩是0,0 谢谢!

    • hasNext()的定义是“如果此扫描仪的输入中有另一个标记,则返回true。此方法可能会在等待输入扫描时阻塞。扫描仪不会前进超过任何输入。” 当我把 standardInput.hasNext() 放在 for 循环中时,程序会向无穷大运行。但是如果我把它放在 while-loop 中,它不会运行到无穷大。这两个程序之间的区别在哪里,为什么其中一个有效而另一个无效? for循环: while-l

    • 在生命数==0之后,while语句为false,必须退出循环。但在这种情况下,即使循环为false,也会执行循环。

    • 我有3个div。当我点击特定的按钮时,每个人都会有类活动。它们的每个div都有一个状态变量,每当它是真的时,我都会向连接到它的div添加class Name='active': 当我点击按钮时,状态改变,但是div没有激活类 当我将函数更改为此时,它会工作: ================================================ =====================

    • 我正在尝试编写一个函数,该函数将取一个整数,将其除以数字,将其相加,如果总和为 我并不是真的在寻找一个最佳的解决方案,我只是想知道为什么这不起作用。