通过提取
,Java编译器是否足够智能以优化下面的循环Double average = new Double( totalTime / callCount );
出于for循环?
public double computeSD( Set values, int callCount, long totalTime ) {
double diffs = 0.0d;
for( Iterator i=values.iterator(); i.hasNext(); ) {
double value = ( ( Double )i.next() ).doubleValue();
Double average = new Double( totalTime / callCount );
diffs += ( value – average.doubleValue() ) * ( value – average.doubleValue() );
}
double variance = diffs / callCount;
return Math.sqrt( variance );
}
答案 0 :(得分:4)
没有什么能阻止字节码编译器(java->字节码)执行优化。当我在赛门铁克工作,并且他们做了一个Java IDE时,编译器编写确实考虑对我们的编译器进行一些优化,但表示没有人(在外部世界中)似乎感兴趣并且关注的是及时(JIT)编译器与现代Sun VM中的HotSpot大致相同。
没有什么可以阻止字节码编译器执行优化,但我不知道有任何这样做。运行时优化非常集中,但在运行时几乎都隐藏了这些优化。
因此,source->字节码编译器可能不会优化它,但VM可能会这样做。如果您使用的是Android,那么它可能不会执行运行时优化。
答案 1 :(得分:4)
Java不会也不能从循环中提取它。
使用'new'关键字将始终导致创建新对象。
你最好使用Double.valueOf()
请参阅Double.valueOf(double)
的javadoc:
“返回表示指定double值的Double实例。如果不需要新的Double实例,通常应优先使用此方法,而不是构造函数Double(double),因为此方法可能会产生明显更好的空间和通过缓存经常请求的值来表现时间。“
如果您使用此方法,则每次都会返回相同的对象,从而减少了创建的对象数量并提高了性能。
然而,使用valueOf
仍然不是你的答案!
valueOf
仍然是一个方法调用,并且方法调用不会被优化掉。它将在循环的每次迭代中调用valueOf
。查看您的方法并计算方法调用。现在它是6,包括hasNext
和new Double
,类似于方法调用。这些都会每次都发生,没有java优化会改变它。你最好从重构中删除尽可能多的方法调用。
答案 2 :(得分:2)
这看起来似乎是一个明显的优化,但我不这么认为,因为它涉及对象实例化。当然,它是一个不可变原始盒子类型的实例化,但仍然不能保证没有副作用。
我不认为任何当前的编译器都可以优化它。为了优化这一点,必须告诉编译器某些类具有特殊属性(考虑到将来可能会发生变化,这可能是一个危险的命题)。也就是说,必须告诉编译器API的细节。这不能仅在语言层面进行优化。
但是,如果您使用double
,则更有可能进行优化(例如使用loop-invariant code motion技术)。
答案 3 :(得分:2)
如果您真的想确定,this question的答案会告诉您如何查看JIT编译器生成的本机代码。
答案 4 :(得分:0)
不是真的。编译器只写出byte-code。如果有什么优化代码,那就是Java虚拟机,这可能取决于平台,实现和执行条件......