6

for循环中什么更好

这:

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

或者:

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

让我们说someMethod()返回一些大的东西。

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

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

4

9 回答 9

11

第二个更好——假设someMethod()没有副作用
它实际上缓存了由someMethod()- 计算的值,因此您不必重新计算它(假设它是一个相对扩展的操作)。

如果确实如此(有副作用)——这两个代码快照是不等价的——你应该做正确的事情。

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

PS
在某些情况下,编译器/JIT 优化器可能会将第一个代码优化为第二个,当然前提是没有副作用。

于 2013-02-04T14:39:40.780 回答
4

如有疑问,请测试。使用分析器。措施。

于 2013-02-04T14:39:47.617 回答
4

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

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

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

于 2013-02-04T14:40:06.167 回答
3

如果循环后不需要这个变量,有一种简单的方法可以将它隐藏在里面:

for (int count = someMethod (), i = 0; i < count; i++)
{
    // some code
}
于 2013-02-04T14:46:09.050 回答
2

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

于 2013-02-04T14:44:02.123 回答
2

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

于 2013-02-04T14:45:11.537 回答
1

关于循环优化最重要的部分是允许 JVM 展开循环。要在第一个变体中这样做,它必须能够内联对someMethod(). 内联有一些预算,它可能会在某个时候被破坏。如果 someMethod() 足够长,JVM 可能会决定它不喜欢内联。

第二个变体更有帮助(对 JIT 编译器)并且可能工作得更好。

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

max不会污染代码,您可以确保多次调用 someMethod() 没有副作用,并且它很紧凑(单衬里)

于 2013-02-06T08:15:11.800 回答
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()很昂贵(如您所假设的),那么“提升”呼叫以使其仅执行一次可能是值得的。

于 2013-02-04T14:55:49.963 回答
0

我对此有点困惑,并对其进行了健全性测试,其中包含 10,000,000 个整数的列表。差异超过两秒,后者更快:

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

于 2019-08-14T08:50:59.103 回答