无法访问的语句:while true 与 if true
Unreachable statement: while true vs if true
我应该如何理解这种 Java 编译器行为?
while (true) return;
System.out.println("I love Java");
// Err: unreachable statement
if (true) return;
System.out.println("I hate Java");
// OK.
谢谢。
编辑:
几分钟后我发现了重点:
在第一种情况下,编译器因无限循环而抛出错误。在这两种情况下,编译器都不会考虑语句中的代码。
编辑二:
现在javac让我印象深刻的是:
if (true) return; // Correct
}
while (true) return; // Correct
}
看起来 javac 知道两个循环中的内容,如果有的话,
但是当你写另一个命令时(如第一个例子)你会得到不等价的行为(这看起来像 javac 忘记了里面的内容loop/if)。
public 静态最终编辑 III:
作为这个答案的结果,我可能会评论(希望是正确的):
if (arg) { ...; return;}
和 while (arg) { ...; return;}
的表达式对于 Java 在语义和句法(字节码)上是等价的,当且仅当 argv
是非常量(或有效的最终类型)表达式。如果 argv
是常量表达式字节码(和行为)可能不同。
免责声明
这个问题不是关于无法访问的语句,而是对逻辑等价表达式的不同处理,例如 while true return
和 if true return
.
在 java 中可以访问语句时有非常严格的规则。这些规则旨在易于评估,而不是 100% 准确。它应该防止基本的编程错误。要推断 java 中的可达性,您必须遵守这些规则,"common logic" 不适用。
这里是 Java 语言规范 14.21. Unreachable Statements
中的规则
An if-then statement can complete normally iff it is reachable.
所以如果没有 else,if-then 之后的语句总是可以访问的
A while statement can complete normally iff at least one of the following is true:
The while statement is reachable and the condition expression is not a constant expression (§15.28) with value true.
There is a reachable break statement that exits the while statement.
条件是常量表达式"true",没有break。因此它没有正常完成。
根据 docs:
Except for the special treatment of while, do, and for statements whose condition expression has the constant value true, the values of expressions are not taken into account in the flow analysis.
如果您稍微更改代码(删除常量表达式),那么它不会触发 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 */
我应该如何理解这种 Java 编译器行为?
while (true) return;
System.out.println("I love Java");
// Err: unreachable statement
if (true) return;
System.out.println("I hate Java");
// OK.
谢谢。
编辑:
几分钟后我发现了重点:
在第一种情况下,编译器因无限循环而抛出错误。在这两种情况下,编译器都不会考虑语句中的代码。
编辑二:
现在javac让我印象深刻的是:
if (true) return; // Correct
}
while (true) return; // Correct
}
看起来 javac 知道两个循环中的内容,如果有的话, 但是当你写另一个命令时(如第一个例子)你会得到不等价的行为(这看起来像 javac 忘记了里面的内容loop/if)。
public 静态最终编辑 III:
作为这个答案的结果,我可能会评论(希望是正确的):
if (arg) { ...; return;}
和 while (arg) { ...; return;}
的表达式对于 Java 在语义和句法(字节码)上是等价的,当且仅当 argv
是非常量(或有效的最终类型)表达式。如果 argv
是常量表达式字节码(和行为)可能不同。
免责声明
这个问题不是关于无法访问的语句,而是对逻辑等价表达式的不同处理,例如 while true return
和 if true return
.
在 java 中可以访问语句时有非常严格的规则。这些规则旨在易于评估,而不是 100% 准确。它应该防止基本的编程错误。要推断 java 中的可达性,您必须遵守这些规则,"common logic" 不适用。
这里是 Java 语言规范 14.21. Unreachable Statements
中的规则An if-then statement can complete normally iff it is reachable.
所以如果没有 else,if-then 之后的语句总是可以访问的
A while statement can complete normally iff at least one of the following is true:
The while statement is reachable and the condition expression is not a constant expression (§15.28) with value true.
There is a reachable break statement that exits the while statement.
条件是常量表达式"true",没有break。因此它没有正常完成。
根据 docs:
Except for the special treatment of while, do, and for statements whose condition expression has the constant value true, the values of expressions are not taken into account in the flow analysis.
如果您稍微更改代码(删除常量表达式),那么它不会触发 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 */