我一般写
for (int i = 0, n = someMethod(); i < n; i++)
优先于
for (int i = 0; i < someMethod(); i++)
避免重复计算someMethod()
。但是,我真的不确定何时需要这样做。 Java在识别每次都会给出相同结果的方法时有多聪明,只需要在循环开始时执行一次?
答案 0 :(得分:4)
我相信作为程序员,您有责任确定需要动态计算for-loop
上限的情况,并相应地解决这些问题。
假设n
的值不依赖于在循环中执行的某些操作,个人而言,我希望它写为
int n = someMethod();
for (int i = 0; i < n; i++);
因为它保留了最常见的for-loop
样式,同时明确定义了上限。
答案 1 :(得分:1)
据我所知,JIT只会检测到它,如果它是一个相当简单的可内联方法。据说,程序员很容易检测到这些情况,这对于JIT编译器来说是一个难以检测的问题。您最好使用final int
来缓存大型方法的结果,因为JIT可以非常轻松地检测到该值无法更改,甚至可以删除数组访问检查以加快循环。
像
这样的东西int[] arr = new int[ 10 ];
for( int i = 0; i < arr.length; i++ ) {
//...
}
或
List< String > list = Arrays.asList( new String[] { ... } );
for( int i = 0; i < list.size(); i++ ) {
//...
}
可能很容易被JIT优化。调用大型或复杂方法的其他循环很容易被证明总是返回相同的值,但size()之类的方法可能内联甚至完全删除。
最后在数组上使用for-each循环。它们衰减到我在数组的情况下发布的第一个循环,并且还可以轻松地进行优化以产生最快的循环。虽然对于非阵列上的每个循环,我更喜欢避免快速循环,因为它们衰减到Iterator循环而不是我发布的第二个循环。对于LinkedList来说,情况并非如此,因为由于O(n)遍历,Iterator比使用get()更快。
这是关于JIT可以做什么来优化循环的所有猜测。重要的是要知道JIT只能优化它可以证明不会改变结果效果的东西。保持简单将使JIT的工作变得更加容易。喜欢使用final关键字。使用最终值或方法允许JIT轻松证明不会发生变化并且可以像疯了一样内联。这是JIT最重要的优化,内联。让这项工作变得轻松,JIT将帮助您大做出任何事情。
这是一个link讨论循环优化,如果JIT不能证明它的优化不会改变任何东西,那么JIT就不能总是优化循环。