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

时间:2015-12-24 13:30:58

标签: java if-statement unreachable-code unreachable-statement

如果我尝试编译

for(;;)
{

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

Java编译器产生错误Unreachable statement。但是,如果我添加另一个“无法访问的”(根据我)break语句并制作它:

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

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

5 个答案:

答案 0 :(得分:57)

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

  

如果if-then语句可以访问,则可以访问then语句。

因此编译器确定then语句(set shell = createobject("wscript.shell") shell.appactivate("Skype for Business") shell.sendkeys "%{F4}" )是可以访问的,无论break;中的条件如何。

还有一点,强调我的:

  

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

     
      
  • 可以访问for语句,有条件表达式,条件表达式不是值为true的常量表达式(第15.28节)。
  •   
  • 有一个可以访问for语句的for语句。
  •   

因此,for语句可以正常完成,因为then语句包含break。如您所知,如果您将break替换为break,则无效。

在本节结尾处解释了基本原理。实质上,return有一种特殊的处理方式,可以使用以下构造:

if

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

答案 1 :(得分:11)

my answer to a similar question中所述,特定构造if(compile-time-false)作为明确的后门免于不可达规则。在这种情况下,编译器会将您的break视为可达。

答案 2 :(得分:7)

来自the JLS

  

if-then语句可以正常完成,如果至少有一个   以下是真的:

     

<强>&GT;可以访问if-then语句,而不是条件表达式   一个值为true的常量表达式。

     

<强>&GT; then语句可以正常完成。

允许if(false)

  

这种能够有条件地编译&#34;对...有重大影响,   和二进制兼容性的关系。如果是一组课程   使用这样一个&#34;标志&#34;变量是编译的,条件代码是   省略,以后只分发一个新版本是不够的   包含标志定义的类或接口。一个   因此,更改为标志的值不是二进制兼容的   预先存在的二进制文件。 (还有其他原因   这种不兼容性,例如在情况下使用常数   switch语句中的标签;)

答案 3 :(得分:4)

基本上,无法访问代码是通过分析程序静态 而不 实际运行代码来检测的。虽然将在运行时检查条件。因此,当进行此分析时,它实际上并未查看条件,只是通过break;检查if是否可访问(可访问)。

答案 4 :(得分:1)

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

因此,很明显无法检测到所有无法访问的语句,但为什么不尝试评估条件呢?现在想象一下,使用的条件不仅仅是false,还有~x == x之类的东西。例如,对于每个truesource),所有这些语句都会打印int x

    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

给出