如果我尝试编译
for(;;)
{
}
System.out.println("End");
Java编译器产生错误Unreachable statement
。但是,如果我添加另一个“无法访问的”(根据我)break
语句并制作它:
for(;;)
{
if(false) break;
}
System.out.println("End");
它编译。为什么不产生错误?
答案 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
之类的东西。例如,对于每个true
(source),所有这些语句都会打印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
给出