Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write Java for loops to avoid repeatedly computing the upper bound

I generally write

for (int i = 0, n = someMethod(); i < n; i++)

in preference to

for (int i = 0; i < someMethod(); i++)

to avoid someMethod() being computed repeatedly. However I'm never really sure when I need to do this. How clever is Java at recognising methods that will give the same result every time and only need to be executed once at the beginning of a loop?

like image 339
Paul Boddington Avatar asked Aug 28 '14 03:08

Paul Boddington


2 Answers

I believe the onus is on you, as the programmer, to identify cases where the upper bound of your for-loop needs to be calculated on the fly and address them accordingly.

Assuming that the value of n does not depend upon some operation that is performed within the loop, personally, I would prefer it written as

int n = someMethod();
for (int i = 0; i < n; i++);

because it preserves the most common style of for-loop while unambiguously defining the upper bound.

like image 166
x4nd3r Avatar answered Sep 28 '22 10:09

x4nd3r


The JIT, as far as I can tell, will only detect this if it's a fairly simple inlineable method. That being said it's very easy for a programmer to detect these cases and is a hard problem for a JIT compiler to detect. Preferably you should use final int to cache results from large methods, as the JIT can very easily detect that value can't change and can even remove array access checks to speed up loops.

Something like

int[] arr = new int[ 10 ];
for( int i = 0; i < arr.length; i++ ) {
    //...
}

or

List< String > list = Arrays.asList( new String[] { ... } );
for( int i = 0; i < list.size(); i++ ) {
    //...
}

can probably be very easily optimized by the JIT. Other loops that call large or complicated methods can't easily be proven to always return the same value, but methods like size() probably could be inlined or even removed completely.

Finally with for-each loops on arrays. They are decayed to the first loop I posted in the case of arrays, and can also easily be optimized to produce the quickest loop. Although for-each loops on non-arrays, I prefer to avoid when it comes to quick loops, as they decay into Iterator loops and not the second loop I posted. That is not true for LinkedList because an Iterator is faster than using get() due to O( n ) traversal.

This is all speculation on what the JIT could do to optimize a loop. It's important to know that the JIT will only optimize something it can prove will not change the resulting effects. Keeping things simple will make the JIT's job much easier. Like using the final keyword. Using final on values or on methods allows the JIT to easily prove that won't change and can inline like crazy. That's the JIT's most important optimization, inlining. Make that job easy and the JIT will help you out in a big way.

Here is a link discussing loop optimizations where the JIT can't always optimize a loop if it can't prove it's optimization won't change anything.

like image 24
Smith_61 Avatar answered Sep 28 '22 10:09

Smith_61