Java最终布尔优化

时间:2014-07-02 09:15:13

标签: java optimization

考虑以下设置:

// debugger class
public class Debug
{
    // setting
    public final static boolean DEBUG = false;

    void print_checked( String s )
    {
        if( DEBUG )
            System.out.print( s );
    }

    void print_unchecked( String s )
    {
        System.out.print( s );
    }
}

// worker class
public class Algorithm
{
    Debug debugger;

    public void heavyWeightAlgorithmImplementation()
    {
        // method 1
        debugger.print_checked( "This method 1" );

        // method 2
        if( debugger.DEBUG )
            debugger.print_unchecked( "Or this method 2" );
    }
}

我已阅读here,Java中的final boolean很可能会被优化出来。但是在我的设置中,if条件在另一个类中,并且当前在print_checked()中实现。 Java是否也优化了函数调用(方法1),还是必须重写方法2中的所有内容?

编辑#1:再次添加静态

3 个答案:

答案 0 :(得分:2)

我已经通过jdk1.7编译了上面的例子,并在jd-gui中打开了* .class文件。
例子:

class Debug
{
    // setting
    public static final boolean DEBUG = false;
    void print_checked( String s )
    {
        if( DEBUG )
            System.out.print( s );
    }
    void print_unchecked( String s )
    {
        System.out.print( s );
    }
}

public class Main 
{
    public static void main(String[] argc)
    {
        Debug debugger = new Debug();
        debugger.print_checked(" This method 1");
        if (debugger.DEBUG)
            debugger.print_unchecked( "Or this method 2");
    }
}

JD-GUI:

// Debug.class
import java.io.PrintStream;
class Debug
{
  public static final boolean DEBUG = false;
  void print_checked(String paramString) {
  }
  void print_unchecked(String paramString) {
    System.out.print(paramString);
  }
}
// Main.class
public class Main
{
  public static void main(String[] paramArrayOfString)
  {
    Debug localDebug = new Debug();
    localDebug.print_checked(" This method 1");
  }
}

你可以看到方法" print_checked"保留在Main.class代码中,但" print_unchecked"被删除了。我不确定,但我认为空方法" print_checked"也可能被Oracle JVM忽略。

答案 1 :(得分:0)

Java随着时间的推移而变化,并且变得更加复杂。所以拿一点盐就可以了。

在javac编译期间,如果编译器可以证明永远不会访问某段代码,那么它将被删除。

在运行时,现代Oracle JVM倾向于以解释模式开始运行字节代码,在这种情况下,它将进行检查,直到JVM认为代码“热”足以进行优化。在这个时候,Hotspot开始了,并且它正朝着这样的观点前进,即假设其他方面的字段将被认为是最终的。此时它将尝试相当积极地预测分支和内联代码。

但是,如果我的记忆回忆起来,运行时不能将非静态字段的最终关键词视为优化的最终关键词,因为有些方法可以在运行时更改这些字段的值。宠物讨厌JVM内部人员。

因此,出于您的选择,我会推荐方法1,因为它减少了需要复制块的位置数。但是,如果可能的话,我会将DEBUG字段设为静态,这样可以更可靠地删除if语句。

答案 2 :(得分:0)

在你的样本中,第一种方法是恕我直言。但是如果你需要一些关于调试的连接操作,那么第二个变量是可取的。

以下是一个例子:

if( debugger.DEBUG )
        debugger.print_unchecked( "Or this method 2" + oldValue + "//" + newValue);

在这种情况下,编译器可以避免不必要的字符串连接和调用toString()方法。

这是我的测试:

public class DebuggerTest {

    static final int ITER_NUM = 5000000;
    public static class Debug
    {
        // setting
        public final static boolean DEBUG = false;
        private final List<String> collector = new ArrayList<String>(ITER_NUM);
        void print_checked( String s )
        {
            if( DEBUG )
                collector.add(s);
        }

        void print_unchecked( String s )
        {
            collector.add(s);
        }
    }

    public static void main(String[] args) {
        Debug debug = new Debug();
        long time = System.currentTimeMillis();
        for (int i = 0; i < ITER_NUM; i++) {
            debug.print_checked("Debug message " + i);
        }
        System.out.println("First: " + (System.currentTimeMillis() - time));
        debug = new Debug();
        time = System.currentTimeMillis();
        for (int i = 0; i < ITER_NUM; i++) {
            if (Debug.DEBUG)
                debug.print_unchecked("Debug message " + i);
        }
        System.out.println("Second: " + (System.currentTimeMillis() - time));
    }
}

结果:

First: 339
Second: 2