Java编译器能够优化掉这段代码吗?

3

Java编译器或运行时(或任何其他语言编译器)是否足够聪明,能够意识到分支3永远不可能发生,并将其优化掉?我看到过许多初学者使用这种“防御性编程”,想知道这种无用的代码是否会保留在字节码中。

import java.util.Random;


class Example
{
    public static void main(String[] args) {
        int x = new Random().nextInt() % 10;
        if ( x < 5 )
        {
            System.out.println("Case 1");
        }
        else
            if ( x >= 5 )
            {
                System.out.println("Case 2");
            }
            else
            {
                System.out.println("Case 3");
            }

    }
}

甚至是更直接的情况
boolean bool = new Random().nextBoolean();
if ( bool )
{
    System.out.println("Case 1");
}
else
    if ( bool )
    {
        System.out.println("Case 2");
    }

1
一个JIT编译器可能会解决这个问题。或者至少会从分析中发现它非常罕见,因此会优化测试并将实际代码移出行内。(javac很少会对其进行优化。) - Hot Licks
3
注意事项:使用nextInt(n)而不是nextInt() % n。它可以处理各种棘手的情况。http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt(int) - Jerry101
1个回答

4

我有的Java 8编译器似乎不能将其优化掉。使用“javap -c”在编译后检查字节码:

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/util/Random
       3: dup
       4: invokespecial #3                  // Method java/util/Random."<init>":()V
       7: invokevirtual #4                  // Method java/util/Random.nextInt:()I
      10: bipush        10
      12: irem
      13: istore_1
      14: iload_1
      15: iconst_5
      16: if_icmpge     30
      19: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      22: ldc           #6                  // String Case 1
      24: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      27: goto          54
      30: iload_1
      31: iconst_5
      32: if_icmplt     46
      35: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      38: ldc           #8                  // String Case 2
      40: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      43: goto          54
      46: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      49: ldc           #9                  // String Case 3
      51: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      54: return
}

字节码中仍存在字符串"Case 3"。


Javac从不优化这些内容。这是JIT编译器的工作。 - leventov
@leventov JIT不会删除死代码,它只是存在那里。话虽如此,它也没有做任何除了存在的事情。如果能够检测到死代码并将其删除,也不会获得任何重要的时间优化。 - user289086

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接