无法访问的声明:如果为true则为true

时间:2017-02-11 12:55:24

标签: java javac unreachable-code

我应该如何理解这种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 returnif true return等逻辑等效表达式的不同处理。

3 个答案:

答案 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 */