1

When I'm making a for loop or a foreach loop, is there an efficiency difference between doing them in these 2 different ways?

For a for loop:

 int x = myArray.size(); for(int ind = 0; ind<x; ind++){ //do stuff } 

vs

 for(int ind = 0; ind<myArray.size(); ind++){ //do stuff } 

for a foreach loop:

 for(String str: myClass.getStringList()){} 

vs

 ArrayList<String>list = myClass.getStringList(); for(String str: list){ } 

I know this is really two different questions but i think they're similar enough to justify being in the same question- correct me if I'm wrong

3
  • 3
    These are micro-optimizations. The motivation for the preferred approach should be readability rather than performance in the above examples.. Commented Aug 8, 2019 at 14:00
  • 2
    Do each a million times, measure, get the average, compare. Commented Aug 8, 2019 at 14:02
  • for there is a difference (measurable?) since the size method is called each iteration; for-each loop is almost the same, getStringList is called only once (14.14.2. The enhanced for statement) Commented Aug 8, 2019 at 14:23

3 Answers 3

0

If .size() and .getStringList() methods are constant there is no difference between them. We say that they are constant if no calculation is required every time is called (for example if say is stored as integer instead count all the elements of the list every time)

But just as advice: if performance is not a current requirement forget it. Prioritize readility always if the code is not a proof of concept.

Sign up to request clarification or add additional context in comments.

Comments

0

The below case is better as it calculates the size of the array only once and it is used for checking inside the for look.

int x = myArray.size(); for(int ind = 0; ind<x; ind++){ //do stuff } 

The following is not an efficient case as compared to the above case as it calculates the size of the array every time when the for loop runs.

for(int ind = 0; ind<myArray.size(); ind++){ //do stuff } 

In case of generics like

List<String> list = new ArrayList<>(); 

it is always recommended to use like this which you have already mentioned.

for(String str: list){ } 

18 Comments

Are you sure this is true? arraylist.size() I thought was constant.
@Sambit That link is about Javascript though.
@Sedrick I believe you are right that it is not calculated every loop, so his wording is off, but I believe it is slightly faster due to not calling the method each time to get the value back but rather a local value, but that is extremely minor of an optimization. Though if you use the length again in the loop then it is useful.
@Sedrick A constant would be private static final int size, no? Which it is not.
|
0

You can compile the methods and compare their bytecode to see the differences.

The biggest difference is between func1 and func2 where func1 only calls size() once, whereas func2 re-calls size() for every iteration. If size() is not cached (most implementations do cache it) then it could be costly to re-compute it. Even in that case the jitter can probably optimize it, especially with a local variable, since it might realize that the list does not change. But if the list were an exposed member then it might need to re-compute the size each time since a separate thread could have modified the list, though it's still very likely to be optimized to assume that the size has not changed.

The only difference between func3 and fun4 is that func4 uses an extra astore and aload since it's storing the list in a local variable, which can probably be optimized away by the jitter.

Ultimately the best way to test efficiency is to measure it.


private void func1() { ArrayList<String> list = new ArrayList<>(); int x = list.size(); for (int i = 0; i < x; i++) System.out.println(list.get(i)); } private void func2() { ArrayList<String> list = new ArrayList<>(); for (int i = 0; i < list.size(); i++) System.out.println(list.get(i)); } private void func3() { for (String str : new ArrayList<String>()) System.out.println(str); } private void func4() { ArrayList<String> list = new ArrayList<>(); for (String str : list) System.out.println(str); } 

private void func1(); ... storing the list ... 8 aload_1 [list] 9 invokevirtual java.util.ArrayList.size() : int [18] // compute list.size() 12 istore_2 [x] // store list.size() 13 iconst_0 14 istore_3 [i] 15 goto 35 ... print ... 32 iinc 3 1 [i] // i++ 35 iload_3 [i] // load i 36 iload_2 [x] // load the already computed list.size() 37 if_icmplt 18 // if i < list.size() goto 18 40 return 

private void func2(); ... storing the list ... 8 iconst_0 9 istore_2 [i] 10 goto 30 ... print ... 27 iinc 2 1 [i] // i++ 30 iload_2 [i] // load i 31 aload_1 [list] // load the list 32 invokevirtual java.util.ArrayList.size() : int [18] // compute list.size() 35 if_icmplt 13 // if i < list.size() goto 13 38 return 

private void func3(); ... storing the list ... 7 invokevirtual java.util.ArrayList.iterator() : java.util.Iterator [50] 10 astore_2 11 goto 31 14 aload_2 15 invokeinterface java.util.Iterator.next() : java.lang.Object [54] [nargs: 1] ... print ... 31 aload_2 32 invokeinterface java.util.Iterator.hasNext() : boolean [60] [nargs: 1] 37 ifne 14 40 return 

private void func4(); ... storing the list ... 7 astore_1 [list] // these are the only extra operations 8 aload_1 [list] // to store the list in a local variable 9 invokevirtual java.util.ArrayList.iterator() : java.util.Iterator [50] 12 astore_3 13 goto 33 16 aload_3 17 invokeinterface java.util.Iterator.next() : java.lang.Object [54] [nargs: 1] ... print ... 33 aload_3 34 invokeinterface java.util.Iterator.hasNext() : boolean [60] [nargs: 1] 39 ifne 16 42 return 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.