为什么 Java 编译器不会为无法访问的 then 语句生成无法访问的语句错误?

Why does a Java Compiler not produce an unreachable statement error for an unreachable then statement?

如果我尝试编译

for(;;)
{

}
System.out.println("End");

Java 编译器产生一个错误 Unreachable statement。但是,如果我添加另一个“unreachable”(据我所知)break 语句并使其成为:

for(;;)
{
    if(false) break;
}
System.out.println("End");

编译通过。为什么它不产生错误?

行为定义在the JLS description of unreachable statements:

The then-statement is reachable iff the if-then statement is reachable.

因此编译器确定 then 语句 (break;) 是可达的,而不管 if.

中的条件如何

更进一步,强调我的:

A basic for statement can complete normally iff at least one of the following is true:

  • The for statement is reachable, there is a condition expression, and the condition expression is not a constant expression (§15.28) with value true.
  • There is a reachable break statement that exits the for statement.

所以for可以正常完成,因为then语句中包含一个break。正如您所注意到的,如果将 break 替换为 return.

,它将不起作用

基本原理在本节末尾进行了解释。实质上,if 有一种特殊的处理方式,允许这样的构造:

if(DEBUG) { ... }

其中 DEBUG 可能是一个编译时间常量。

来自the JLS

An if-then statement can complete normally if at least one of the following is true:

> The if-then statement is reachable and the condition expression is not a constant expression whose value is true.

> The then-statement can complete normally.

所以if(false)是允许的。

This ability to "conditionally compile" has a significant impact on, and relationship to, binary compatibility. If a set of classes that use such a "flag" variable are compiled and conditional code is omitted, it does not suffice later to distribute just a new version of the class or interface that contains the definition of the flag. A change to the value of a flag is, therefore, not binary compatible with pre-existing binaries . (There are other reasons for such incompatibility as well, such as the use of constants in case labels in switch statements;)

my answer to a similar question 中所述,特定构造 if(compile-time-false) 作为显式后门不受不可访问性规则的约束。在这种情况下,编译器因此将您的 break 视为可访问。

基本上无法访问的代码是通过静态without[=20]分析程序检测到的=] 实际上是 运行 代码。而条件将在 运行时 检查。因此,当进行此分析时,它实际上并没有查看条件,而只是检查 break; 是否可以通过 if.[=12 访问(可访问) =]

Java 没有检测到 all 不可访问语句的核心原因是通常无法回答代码是否可访问。这是因为 halting problem 在图灵机上是不可判定的。

所以,很明显无法检测到所有无法访问的语句,但为什么不尝试评估条件呢?现在想象一下,使用的条件不仅仅是 false,而是 ~x == x。例如,所有这些语句将为每个 int x (source) 打印 true

    System.out.println((x + x & 1) == 0);
    System.out.println((x + -x & 1) == 0);
    System.out.println((-x & 1) == (x & 1));
    System.out.println(((-x ^ x) & 1) == 0);
    System.out.println((x * 0x80 & 0x56) == 0);
    System.out.println((x << 1 ^ 0x1765) != 0);

语句可能相当复杂;解决它们需要时间。它会显着增加构建时间,毕竟它不会检测所有无法访问的语句。编译器旨在付出一些努力,但不会为此花费太多时间。

剩下的唯一问题是:在哪里停止解析条件?其原因似乎没有数学依据,而是基于使用场景。 JLS-14.21

给出了您的特定案例的基本原理