Overall the gain will be minimal in the case of ArrayList
that calls a method and has some cost.
Already did a test in the O.R.. The gain really is very low and it only pays to worry about it if the loop body is very fast, then the call of the method several times can weigh.
In the case of array There will be even less gain. Both access a variable directly, the only difference is that access to the property will require indirect access (via a pointer) to the object and access to the local variable will be done right there.
I think not in Java, but in C# even a property would be made inline having the same gain of array.
Optimizing
Nor do I say that there is any harm in always preferring to cache the value before. Unless the compiler or Jitter do some optimization by having the size checked inside the loop and when the size is checked off the optimization does not occur. Usually there is great gain in removing the access range overflow check within the loop if the compiler/Jitter can identify that it will never leave the limit. One of the ways to ensure this is to use a for each
. Another is for the compiler to be smart and to verify that the condition plus use always produces contents within the range. The check is done inside the loop. What is outside the loop is not reliable information, it may even give error as shown below.
Semantics
But note that in addition to performance you may have a better reason to cache the size. Semantics is different in both cases.
You shouldn’t do this, but if you change the size of the data collection within the loop and the size was curled off it, it might not have the expected result. The die that indicates the end of the loop no longer matches the reality of the object.
I made an example showing the difference:
import java.util.*;
import java.lang.*;
class Main {
public static void main (String[] args) throws java.lang.Exception {
ArrayList<Integer> x = new ArrayList<Integer>();
x.add(1); x.add(2); x.add(3); x.add(4); x.add(5);
for (int i = 0; i < x.size(); i++) {
if (i % 2 == 0) { //retira os elementos pares
x.remove(i);
}
System.out.println("Tamanho atual = " + x.size() + ", i = " + i); //só para ajudar visualizar
}
System.out.println("---");
for (int i = 0; i < x.size(); i++) System.out.println(x.get(i));
System.out.println("---------------------");
x = new ArrayList<Integer>();
x.add(1); x.add(2); x.add(3); x.add(4); x.add(5);
int tamanho = x.size();
for (int i = 0; i < tamanho; i++) {
if (i % 2 == 0) x.remove(i);
System.out.println("Tamanho atual = " + x.size() + ", i = " + i); //só para ajudar visualizar
}
System.out.println("---");
for (int i = 0; i < x.size(); i++) System.out.println(x.get(i));
}
}
Behold as it gets in the ideone. And in the repl it.. Also put on the Github for future reference. Gives error by popping the existing track, because the loop is with a lagged information.
There is another problem of different semantics that is not the case of the question, but worth the information. You may use a method to take a value and decide whether to close the loop. This method may have a side effect. Is it desirable that this effect occurs at each iteration or should it only occur once? This is important.
In the case of an array no, as
length
is a property, not a method, here has more details– Marco Giovanni
+1, I read about in a performance book that talked about.
– Marconi
A simple but good question. I had never thought about it. I am now beginning to open my mind more to these details.
– Rafael Weber