我应该如何理解这种Java编译器行为?
while (true) return;
System.out.println("I love Java");
// Err: unreachable statement
if (true) return;
System.out.println("I hate Java");
// OK.
感谢。
修改
几分钟后我发现了这一点:
在第一种情况下,编译器因无限循环而抛出错误。在这两种情况下,编译器都不会考虑语句结果中的代码。
编辑II:
现在让我对javac印象深刻的是:
if (true) return; // Correct
}
while (true) return; // Correct
}
看起来javac知道两个循环内部是什么,如果结果, 但是当你编写另一个命令时(如在第一个例子中),你会得到非等效的行为(看起来像javac忘记了循环里面的内容/ if)。
公共静态决赛编辑III:
作为这个答案的结果,我可能会说(希望是正确的):
表达式if (arg) { ...; return;}
和while (arg) { ...; return;}
在语义和语法上(在字节码中)对于Java iff argv
是非常量(或有效的最终类型)表达式。如果argv
是常量表达式,则字节码(和行为)可能不同。
声明
这个问题不是在无法访问的语句上,而是对while true return
和if true return
等逻辑等效表达式的不同处理。
答案 0 :(得分:14)
在java中可以访问语句时有非常严格的规则。这些规则的设计易于评估,而不是100%精确。它应该防止基本的编程错误。为了推断java中的可达性,你只能使用这些规则,“常用逻辑”不适用。
以下是Java语言规范14.21. Unreachable Statements
中的规则if-then语句可以正常完成,如果可以访问的话。
因此,如果没有else,if-then之后的语句总是可以访问
如果至少满足下列条件之一,则while语句可以正常完成:
可以访问while语句,条件表达式不是值为true的常量表达式(第15.28节)。
有一个可到达的break语句退出while语句。
条件是一个常量表达式“true”,没有中断。因此它无法正常完成。
答案 1 :(得分:5)
根据docs:
除了对while,do和for条件表达式具有常量值true的语句的特殊处理外,在流分析中不考虑表达式的值。
答案 2 :(得分:2)
如果稍微更改代码(删除常量表达式),那么它不会触发javac可达性,它实际上会为两者生成相同的字节码。
static boolean flag = true;
static void twhile(){
while (flag) return;
System.out.println("Java");
}
static void tif(){
if (flag) return;
System.out.println("Java");
}
生成的字节码:
static void twhile();
descriptor: ()V
flags: ACC_STATIC
Code:
stack=2, locals=0, args_size=0
StackMap locals:
StackMap stack:
0: getstatic #10 // Field flag:Z
3: ifeq 7
6: return
StackMap locals:
StackMap stack:
7: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
10: ldc #26 // String Java
12: invokevirtual #28 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
15: return
LineNumberTable:
line 8: 0
line 9: 7
line 10: 15
LocalVariableTable:
Start Length Slot Name Signature
StackMapTable: number_of_entries = 1
frame_type = 7 /* same */
static void tif();
descriptor: ()V
flags: ACC_STATIC
Code:
stack=2, locals=0, args_size=0
StackMap locals:
StackMap stack:
0: getstatic #10 // Field flag:Z
3: ifeq 7
6: return
StackMap locals:
StackMap stack:
7: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
10: ldc #26 // String Java
12: invokevirtual #28 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
15: return
LineNumberTable:
line 12: 0
line 13: 7
line 14: 15
LocalVariableTable:
Start Length Slot Name Signature
StackMapTable: number_of_entries = 1
frame_type = 7 /* same */