Java中的For循环优化
我今天在Java教程中阅读了以下代码
StackTraceElement elements[] = e.getStackTrace();
for (int i = 0, n = elements.length; i < n; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
作为一名新手,我可能会编写如下代码
StackTraceElement elements[] = e.getStackTrace();
for (int i = 0; i < elements.length; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
或者像下面这样
int n = elements.length;
for (int i = 0; i < n; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
我只是想问他们之间有什么区别?还有其他更好的方法来优化Java中的for循环吗
# 1 楼答案
优化的黄金法则是,不要
第二条金科玉律是,现在还没有
第三条黄金法则实际上是一个问题,你衡量过了吗
回答你的问题,遵循团队中公认的标准:你的代码不应该有任何不同,除非它做了一些真正不同的事情。也就是说,在一个好的团队中,代码都是相似的、乏味的。任何让开的地方都会有一个巨大的闪光标志,上面写着:“小心,这是规则的例外!”除非你真的想这么说,否则就随别人的便
现在,就代码而言,答案在编译器中:
编译成
正如您所看到的,
a()
和c()
只在variable assignment中不同,因此在JVM中的行为几乎相同,无论是否为JITtedb()
略有不同:这里,在循环中调用arraylength
。正如@thurstycrow所指出的,这不一定是性能问题,但可能是所以,当谈到现实生活中的表现时,你需要确保它值得考虑。检查堆栈跟踪的代码几乎永远不值得优化,,因为你不需要一次又一次地获取堆栈跟踪。此外,我认为日志记录比数组长度检查要昂贵得多
但是,如果我们假设您需要优化这段特定代码,比如说您正在编写一个定制的监视工具来检查抛出的所有异常,您希望它非常慢,而不是非常慢(您知道,收集堆栈跟踪非常昂贵;导航它通常非常便宜),您需要在野外测量它,因为JIT可以并且将考虑在这段代码周围发生的一切
但这是一个无聊的答案,所以尽管我们知道这没有多大意义,但我们还是要做一些基准测试——毕竟,我们可以,为什么不呢?你可以使用的一个很好的基准测试工具是JMH;你可以按照教程去玩它,或者直接抓住这个答案
基准是
(稍后有更多关于
a0
的信息;包括每个和流的答案)。当我们运行它时我们可以看到,这三种方法都是如此之快,以至于同一种方法在运行几次时会产生非常不同的测量结果。对于这个例子,我就到此为止。对于您的实际情况,请随意使用产生问题的实际代码
PS.添加了for each和流媒体解决方案。正如你所看到的,每一个都差不多(虽然可读性更强);溪流明显变慢了。我将把这两种解决方案的^{} examination 留给读者作为练习
# 2 楼答案
我会这样做:
# 3 楼答案
实际上,最好不要将数组长度存储到变量中,因为每次迭代都必须进行额外的数组边界检查。看看this video(从28:00开始)。它详细描述了JIT编译器为优化代码所做的努力
# 4 楼答案
没什么,完全一样。除了将
element.length
保存在变量中并使用该变量。他们在同一时间做同样的事。最后一个例子是最好的,因为它是最容易理解的imho# 5 楼答案
与第一个版本不同的是,代码每次都必须取消对
elements
的引用。从理论上讲,将值存储在变量中应该更有效,但这种操作非常便宜,在实践中几乎不会注意到差异与第二个版本的区别主要在于,在for循环的范围之外引入了变量
n
。也就是说,如果您想将n
重新用作下面的变量名,则只能在其类型相同(在本例中为int
)的情况下才能这样做# 6 楼答案
您也可以按如下方式编写,以简化代码