Java for循环性能

时间:2013-02-04 14:38:00

标签: java performance

for loop

有什么好处

此:

for(int i = 0; i<someMethod(); i++)
{//some code
 }

或:

int a = someMethod();
for(int i = 0; i<a; i++)
{//some code
 }

我们只是说 someMethod()会返回一些大的内容。

第一种方法会在每个循环中执行 someMethod(),从而降低速度,第二种方法更快但是假设在应用程序中有很多类似的循环,因此声明 a 变量vill消耗更多内存。

那么更好,或者我只是在愚蠢地思考。

9 个答案:

答案 0 :(得分:11)

第二个更好 - 假设someMethod()没有side effects
它实际上缓存了由someMethod()计算的值 - 所以你不必重新计算它(假设它是一个相对广泛的操作)。

如果有(有副作用) - 两个代码段不等同 - 你应该做正确

关于“变量a的大小” - 无论如何都不是问题,在计算之前,someMethod()的返回值需要存储在某个中间临时变量上(甚至如果不是这种情况,一个整数的大小可以忽略不计。)

P.S。
在某些情况下,编译器/ JIT优化器可能会将第一个代码优化为第二个代码,假设当然没有副作用。

答案 1 :(得分:4)

如有疑问,请进行测试。使用分析器。测量

答案 2 :(得分:4)

假设迭代顺序不相关,并且假设您真的想要对代码进行纳米优化,那么您可以这样做:

for (int i=someMethod(); i-->0;) {
  //some code
}

但是另外一个局部变量(你的a)并不是一个负担。在实践中,这与您的第二个版本没有太大区别。

答案 3 :(得分:3)

如果你在循环后不需要这个变量,可以通过简单的方法将其隐藏在里面:

for (int count = someMethod (), i = 0; i < count; i++)
{
    // some code
}

答案 4 :(得分:2)

这实际上取决于生成someMethod()的输出所需的时间。内存使用量也是一样的,因为someMethod()首先必须生成输出然后存储它。第二种方法保护你的cpu从每个循环计算相同的输出,它不应该占用更多的内存。所以第二个更好。

答案 5 :(得分:2)

我不认为变量a的内存消耗是一个问题,因为它是一个int并且在64位机器上需要192位。所以我更喜欢第二种选择,因为它的执行效率更高。

答案 6 :(得分:1)

关于循环优化的最重要部分是允许JVM展开循环。要在第一个版本中执行此操作,必须能够内联对someMethod()的调用。内联有一些预算,可能会在某些时候被破坏。如果someMethod()足够长,JVM可能会认为它不想内联。

第二个变体对JIT编译器更有帮助,并且可能更好。

我放下循环的方法是: for (int i=0, max=someMethod(); i<max; i++){...}

max不会污染代码,您可以确保多次调用someMethod()及其紧凑(单线程)没有副作用

答案 7 :(得分:0)

如果你需要优化它,那么这是干净/显而易见的方法:

int a = someMethod();
for (int i = 0; i < a; i++) {
    //some code
}

@dystroy建议的替代版本

for (int i=someMethod(); i-->0;) {
    //some code
}

......有三个问题。

  • 他在相反的方向迭代。

  • 该迭代是非惯用的,因此可读性较差。特别是如果你忽略了Java风格指南,并且没有把空格放在你应该的位置。

  • 没有证据表明代码实际上会比更惯用的版本更快......特别是一旦JIT编译器对它们进行了优化。 (即使可读性较低的版本更快,差异也可能微不足道。)

另一方面,如果someMethod()价格昂贵(如您所假设的那样),那么“提升”通话以便只进行一次,这可能是值得的。

答案 8 :(得分:0)

我对它有些困惑,并且对其中的10,000,000个整数进行了完整性测试。差异超过2秒,而后者更快:

int a = someMethod(); for(int i = 0; i<a; i++) {//some code }

我在Java 8(MacBook Pro,2.2 GHz Intel Core i7)上的结果是:

使用列表对象: 开始于1565772380899, 结束于1565772381632

“ for”表达式中的

调用列表: 开始于1565772381633, 结束于1565772384888