46
List<String> flowers = new ArrayList<String>();

My for loop currently looks like this...

for (int i = 0; i < flowers.size(); i++) {
...
}

OR should I change this to look like the code given below

int size = flowers.size();
for (int i = 0; i < size; i++) {
...
}

Which is more performant (assuming I have a large array of flowers), I am guessing it should be the latter.

Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
Joe
  • 14,513
  • 28
  • 82
  • 144
  • 14
    I think the underlying mechanics will probably optimise that for you. – sje397 May 23 '11 at 06:24
  • one would hope that the java compiler would make that optimization for you. – Yaur May 23 '11 at 06:24
  • If Java didn't make the optimisation, then yes, the latter would be better to avoid calling .size() every time. But Java is quite clever. – Owen May 23 '11 at 06:27
  • 9
    @sje397, @Yaur: It may or may not be able to optimize that. It depends on the JVM **and** the code inside the loop. If the code inside changes the size of `flowers` (and that might be very tricky to check!) then it **can't** be optimized. – Joachim Sauer May 23 '11 at 06:27
  • ... and the JVM has to be pessimistic: it needs to prove that no code inside the loop (including any functions called there) can change `flowers`. This is especially hard in modern languages such as Java) where code can change at runtime, e.g. through loading extra code. – MSalters May 23 '11 at 08:26
  • 3
    @sje397 no, it can't be optimized because size() may have side-effects – Adam Dyga Oct 12 '12 at 10:31

15 Answers15

60

It is better to use for-each loop [more readable]

for (Flower flower :flowers){
    //...
}

I have dumped instructions using javap for the following code:

public void forLoop1() {
    List<String> lst = new ArrayList<String>();
    for (int i = 0; i < lst.size(); i++) {
        System.out.println("hi");
    }
}

public void forLoop2() {
    List<String> lst = new ArrayList<String>();
    int size = lst.size();
    for (int i = 0; i < size; i++) {
        System.out.println("hi");
    }
}

public void forLoop1();
  Code:
   0:   new     #2; //class java/util/ArrayList
   3:   dup
   4:   invokespecial   #3; //Method java/util/ArrayList."<init>":()V
   7:   astore_1
   8:   iconst_0
   9:   istore_2
   10:  iload_2
   11:  aload_1
   12:  invokeinterface #4,  1; //InterfaceMethod java/util/List.size:()I
   17:  if_icmpge       34
   20:  getstatic       #5; //Field java/lang/System.out:Ljava/io/PrintStream;
   23:  ldc     #6; //String hi
   25:  invokevirtual   #7; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
   28:  iinc    2, 1
   31:  goto    10
   34:  return

public void forLoop2();
  Code:
   0:   new     #2; //class java/util/ArrayList
   3:   dup
   4:   invokespecial   #3; //Method java/util/ArrayList."<init>":()V
   7:   astore_1
   8:   aload_1
   9:   invokeinterface #4,  1; //InterfaceMethod java/util/List.size:()I
   14:  istore_2
   15:  iconst_0
   16:  istore_3
   17:  iload_3
   18:  iload_2
   19:  if_icmpge       36
   22:  getstatic       #5; //Field java/lang/System.out:Ljava/io/PrintStream;
   25:  ldc     #6; //String hi
   27:  invokevirtual   #7; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
   30:  iinc    3, 1
   33:  goto    17
   36:  return

It doesn't optimize for me.

java version "1.6.0_22" Java(TM) SE Runtime Environment (build 1.6.0_22-b04) Java HotSpot(TM) Client VM (build 17.1-b03, mixed mode, sharing)

So if you need to choose from mentioned two, go for second, but I personally would go for for-each.


for-each Performance

From Item 46 in Effective Java by Joshua Bloch :

The for-each loop, introduced in release 1.5, gets rid of the clutter and the opportunity for error by hiding the iterator or index variable completely. The resulting idiom applies equally to collections and arrays:

// The preferred idiom for iterating over collections and arrays
for (Element e : elements) {
    doSomething(e);
}

When you see the colon (:), read it as “in.” Thus, the loop above reads as “for each element e in elements.” Note that there is no performance penalty for using the for-each loop, even for arrays. In fact, it may offer a slight performance advantage over an ordinary for loop in some circumstances, as it computes the limit of the array index only once. While you can do this by hand (Item 45), programmers don’t always do so.


See Also

Community
  • 1
  • 1
jmj
  • 237,923
  • 42
  • 401
  • 438
  • 12
    -1: That wasn't the question, explain which of the constructs that is the best, this is just a comment... – dacwe May 23 '11 at 06:41
  • 2
    This isn't a good answer. Java's for each loop is twice as slow as the OPs question, and 4 times as slow as optimized loops. – David Titarenco May 23 '11 at 06:43
  • I ran it in practice both against a Collection and an array, it's significantly slower in both cases. Maybe in `theory` it's not supposed to be a performance penalty, but it is. – David Titarenco May 23 '11 at 06:53
  • -1. As we don't have details about the underlying implementation, we can't be sure for each loops fit the requirements. – Agemen May 23 '11 at 06:54
  • 7
    +1 It **is** a good answer because when your over all performance is bad, the **last thing** you should do is doing that sort of micro-optimization. Performance issues are solved with multithreading and looking at complexity (O-Notation, includes choosing appropriate collection types). A solid +1 for readability. Sometimes it helps **not** to think about fine tuning. (general statement, Joe may have good reasons for his question) – Andreas Dolk May 23 '11 at 07:04
  • 23
    *It doesn't optimize for me.* -- FYI, javac does very few optimizations. Optimizations like these are done by the JIT compiler. – aioobe May 23 '11 at 07:32
  • 2
    What a solid answer!!! I am busy with Effective Java. What a awesome read as well. The only additional thing to check is if flowers is null. But it is not applicable to the above example. – Koekiebox May 24 '11 at 15:42
19

Sorry to say, but @Jigar's answer is incorrect. This is the correct answer. (tldr; don't use for : each).

import java.util.ArrayList;
import java.util.List;

public class LoopTest {

    public static void main(String s[]) {

        long start, end;

        List<Integer> a =  new ArrayList<Integer>();

        for (int i = 0; i < 2500000; i++) {
            a.add(i);
        }

        ///// TESTING FOR : EACH LOOP

        start = System.currentTimeMillis();

        for (Integer j : a) {
            int x = j + 3;
        }

        end = System.currentTimeMillis();

        System.out.println(end - start
                + " milli seconds for [ Integer j : a ] ");

        ////// TESTING DEFAULT LOOP

        start = System.currentTimeMillis();
        for (int i = 0; i < a.size(); i++) {
            int x = a.get(i) + 3;
        }

        end = System.currentTimeMillis();

        System.out.println(end - start
                + " milli seconds for [ int i = 0; i < a.length; i++ ] ");


        ////// TESTING SLIGHTLY OPTIMIZED LOOP

        start = System.currentTimeMillis();
        int size = a.size();
        for (int i = 0; i < size; i++) {
            int x = a.get(i) + 3;
        }

        end = System.currentTimeMillis();

        System.out.println(end - start
                + " milli seconds for [ int i = 0; i < size; i++ ] ");        

        //// TESTING MORE OPTIMIZED LOOP

        start = System.currentTimeMillis();
        for (int i = size; --i >= 0;) {
            int x = a.get(i) + 3;
        }

        end = System.currentTimeMillis();

        System.out.println(end - start
                + " milli seconds for [ int i = size; --i >= 0; ] ");       

    }

}

The results:

96 milli seconds for [ Integer j : a ] 
57 milli seconds for [ int i = 0; i < a.length; i++ ] 
31 milli seconds for [ int i = 0; i < size; i++ ] 
31 milli seconds for [ int i = size; --i >= 0; ] 

You can make up your own mind, but too much attribution is given to the JVM optimizer. You still have to be smart with your own code, and using for : each notation is NOT a good idea (almost ever). As you can see, you have a good idea by putting size in its own variable.

Even though some of these optimization may be JVM-dependent (and some may kick in with the JIT), it's important to know what Java does and what Java doesn't do.

David Titarenco
  • 32,662
  • 13
  • 66
  • 111
  • 3
    u r right `for : each` is always been slow and call to frequent `.size()` is some what slow than assign to one varialble – Ravi Parekh May 23 '11 at 07:00
  • 4
    Saying "that using for-each notation is NOT a good idea (almost ever)" is pretty silly. In the absolute majority of the cases, you are going to prefer readability over performance. In the few cases where your loop is a performance bottelneck, it might be worth it to investigate whether there is a more performant option. – Alderath Apr 05 '12 at 08:47
  • 13
    I think the problem with your for each sample code is with auto boxing and unboxing. – Raze Apr 11 '12 at 08:03
  • for each also creates an iterator - an object in heap, so lot's of for each can increasy memory preassure. – Denis Gladkiy Oct 10 '14 at 13:18
  • @dfa - you do realize this answer is 10 years old, right? And that it predates JMH by several years? – David Titarenco Nov 28 '21 at 00:45
11

The JVM can't optimize it because size() is a method, and JVM can't (and won't try to) determine that the size() will always return the same value in this context. Provided size() value doesn't change, the second one is slightly more performant, but the gain is so, so slight that you don't really have to even consider using it.

mipe34
  • 5,596
  • 3
  • 26
  • 38
Raze
  • 2,175
  • 14
  • 30
9

If performance is critical, use the plain counter loop, however for 98% of cases, clarity and simplicity of code is far more important (like 1000x or more) and you should use a for-each loop.

@David points out that using a counter is faster, but I would point out that even for 10,000 entries, the difference is sub-microsecond.

If you have a collection of more than 10,000 entries it is highly likely you shouldn't be brute force iterating over every possibility. It is more likely a collection with a lookup like a Map is a better solution for whatever you have in mind. If you have far less than 10,000 entries performance is less likely to be important.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
6

The behavior is different if the array list changes while iterating. But I guess you don't do that. According to my test, the latter is usually faster (specially on systems like Android). I would write it as follows:

for (int i = 0, size = flowers.size(); i < size; i++) {
    ...
}
Thomas Mueller
  • 48,905
  • 14
  • 116
  • 132
4

From the Java language specification (14.14.1):

The basic for statement executes some initialization code, then executes an Expression, a Statement, and some update code repeatedly until the value of the Expression is false.

The Expression is i < flowers.size() in your first example and it is evaluated once in every iteration. In your special case it shouldn't make a noteable difference, because flowers.getSize() on ArrayList is a very short method. But, in general, if the result of the expression is the same for each iteration and expensive, then do a pre calculation.

Consequence: this has to produce the same output in every implementation of a Java virtual machine and proves, that Expression is evaluate once in each iteration:

int counter2 = 10;
for (int counter1 = 0; counter1 < counter2; counter1++) {
  System.out.println(counter1 + ", " + counter2);
  counter2--;
}

Output:

0, 10
1, 9
2, 8
3, 7
4, 6
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
3

Also, if you wonder whether using a method call as a source collection has any performance implications. That is - will the method be called many times - the answer is no. Here's an example:

import java.util.*;
public class TestForeach {
    public static void main (String[] args) {

        for (String s : getStrings()) {
            System.out.println("The string was: "+s);
        }
    } 

    private static List<String> getStrings() {
        System.out.println("IN GET STRINGS");
        return Arrays.asList("A","B","C");
    }
}

This will result in:

IN GET STRINGS
The string was: A
The string was: B
The string was: C

Therefore, the method will only be called once.

ACV
  • 9,964
  • 5
  • 76
  • 81
3

The best option is

[ int i = 0; i < size; i++ ]

Your results will vary based on which JVM and other setting like -client vs -server because some of the measurements are so tiny you need to use nano seconds to measure, and you need to do many tests otherwise you end up with the GC messing with the results. Also these kinds of tests have a habit of the JVM optimizing the loop to nothing. I tried to eliminate that risk by putting the variable that it modifies at the end of the code to the screen.

1.6
-server
7.968242071 milli seconds for [ Integer j : a ] 
7.206275775999999 milli seconds for [ int i = 0; i < a.length; i++ ]  
1.5864E-5 milli seconds for [ int i = 0; i < size; i++ ] 
14.774186076999998 milli seconds for [ int i = size; --i >= 0; ] 

-client
83.36101683999999 milli seconds for [ Integer j : a ] 
44.288568631 milli seconds for [ int i = 0; i < a.length; i++ ]  
2.3191E-5 milli seconds for [ int i = 0; i < size; i++ ] 
24.826621246 milli seconds for [ int i = size; --i >= 0; ] 

1.7

-server
7.029150422 milli seconds for [ Integer j : a ] 
6.6269827779999995 milli seconds for [ int i = 0; i < a.length; i++ ]  
1.3852E-5 milli seconds for [ int i = 0; i < size; i++ ] 
13.842110377 milli seconds for [ int i = size; --i >= 0; ] 
13.868426141 milli seconds for [ int i = a.size()-1; i >= 0; i-- ] 
1.6618000000000003E-5 milli seconds for [ int i = 0; i < a.size(); i++ ] 

-client
7.382479727 milli seconds for [ Integer j : a ] 
6.748068759 milli seconds for [ int i = 0; i < a.length; i++ ]  
1.4162999999999998E-5 milli seconds for [ int i = 0; i < size; i++ ] 
13.951547335999999 milli seconds for [ int i = size; --i >= 0; ] 
13.929234053999998 milli seconds for [ int i = a.size()-1; i >= 0; i-- ] 
1.6873E-5 milli seconds for [ int i = 0; i < a.size(); i++ ] 

Test code:

public static void main(String s[]) {
long start=0, end = 0, delta = 0;
//int[] a = new int[2500000];
List<Integer> a = new ArrayList<Integer>();
int x = 0;

for (int i = 0; i < 2500000; i++) {
    a.add(i);
}

start=0; end = 0; delta = 0;
for (int ctr = 0; ctr < 1000; ctr++) {
    start = System.nanoTime();
    for (Integer j : a) {
         x = j + 3;
    }
    end = System.nanoTime();
    delta += end - start;
}
System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ Integer j : a ] ");


start=0; end = 0; delta = 0;
for (int ctr = 0; ctr < 1000; ctr++) {
    start = System.nanoTime();
    for (int i = 0; i < a.size(); i++) {
         x = a.get(i) + 3;
    }
    end = System.nanoTime();
    delta += end - start;
}
System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = 0; i < a.length; i++ ]  ");

int size = a.size();

start=0; end = 0; delta = 0;
for (int ctr = 0; ctr < 1000; ctr++) {
    start = System.currentTimeMillis();

    for (int i = 0; i < size; i++) {
         x = a.get(i) + 3;
    }
    end = System.currentTimeMillis();
    delta += end - start;
}
System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = 0; i < size; i++ ] ");

start=0; end = 0; delta = 0;
for (int ctr = 0; ctr < 1000; ctr++) {
    start = System.nanoTime();
    for (int i = size; --i >= 0;) {
         x = a.get(i) + 3;
    }
    end = System.nanoTime();
    delta += end - start;
}
System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = size; --i >= 0; ] ");


start=0; end = 0; delta = 0;
for (int ctr = 0; ctr < 1000; ctr++) {
    start = System.nanoTime();
    for (int i = a.size()-1; i >= 0; i--) {
         x = a.get(i) + 3;
    }
    end = System.nanoTime();
    delta += end - start;
}
System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = a.size()-1; i >= 0; i-- ] ");

start=0; end = 0; delta = 0;
for (int ctr = 0; ctr < 1000; ctr++) {
    start = System.currentTimeMillis();

    for (int i = 0; i < a.size(); i++) {
         x = a.get(i) + 3;
    }
    end = System.currentTimeMillis();
    delta += end - start;
}
System.out.println(Math.pow(10, -6) * delta / 1000 + " milli seconds for [ int i = 0; i < a.size(); i++ ] ");        

System.out.println(x);
}
medv4380
  • 493
  • 1
  • 5
  • 6
  • Nice data collection. But some issues: 1. Don't switch timers used! (*They return different units so the values reported are incorrect!*) 2. Update for consistent result and formatting so all numbers are using the same base 3. Run entire set of tests multiple times within same process to check for anomalies. Also "fastest" is not necessarily "best" ;-) –  Jan 27 '12 at 19:46
2

This is just a clarification by example of how situational this is.

I tested executions of the "normal" for loop for (int i = 0; i < list.size(); i++) and a micro optimized for loop for (int i = -1, size = list.size(); ++i < size;). I ran the tests both in eclipse from the command line and noticed a HUGE difference.

Results from running in eclipse:

Time for Original: 32552 ms   Time for MicroOptimized 32707 ms
Fastest Loop: Original
Slowest loop takes 0.47616121897272057% more time

Results from running from commandline:

Time for Original: 274489 ms   Time for MicroOptimized 30516 ms
Fastest Loop: MicroOptimized
Slowest loop takes 799.4920697339101% more time

So in eclipse, the two for loops take the same time, but when run from the command line, the original version takes 800% more time than the microoptimized version. The magnitude of the difference blows my mind. I guess that eclipse uses a different JVM which applies some smart optimization tricks.

This doesn't mean that you should start using the micro optimized version however. In almost all cases, the lists you iterate over will likely be so small that the performance difference is negligible. And the readability gained from using the standard version which everyone will recognize and understand much more quickly is more beneficial than a non-noticeable performance increase.

For completeness, this is the code I ran:

public static void main(String[] args) {
        List<Byte> list = initializeList();
        byte value = 0;
        final int NUM_LOOPS = 100;

        long startOriginal, startOptimized, endOriginal, endOptimized;

        startOptimized = System.currentTimeMillis();
        for (int j = 0; j < NUM_LOOPS; j++) {
            for (int i = -1, size = list.size(); ++i < size;) {
                value = list.get(i);
            }
        }
        endOptimized = System.currentTimeMillis();

        startOriginal = System.currentTimeMillis();
        for (int j = 0; j < NUM_LOOPS; j++) {
            for (int i = 0; i < list.size(); i++) {
                value = list.get(i);
            }
        }
        endOriginal = System.currentTimeMillis();

        System.out.println(value);
        printResults(startOriginal, endOriginal, startOptimized, endOptimized);
    }

    private static void printResults(long startOriginal, long endOriginal,
            long startOptimized, long endOptimized) {

        long timeOriginal = endOriginal - startOriginal;
        long timeOptimized = endOptimized - startOptimized;

        long diff = Math.abs(timeOriginal - timeOptimized);
        long min = Math.min(timeOriginal, timeOptimized);

        System.out.println("Time for Original: " + timeOriginal + " ms"
                + "   Time for MicroOptimized " + timeOptimized + " ms");

        System.out.println("Fastest Loop: "
                + ((timeOriginal < timeOptimized) ? "Original"
                        : "MicroOptimized"));

        System.out.println("Slowest loop takes " + ((double) 100 * diff / min)
                + "% more time");       
    }

    public static List<Byte> initializeList(){
        List<Byte> list = new ArrayList<Byte>();
        final Byte ONE = new Byte((byte) 1);

        for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
            list.add(ONE);
        }

        return list;
    }
}
Uwe Allner
  • 3,399
  • 9
  • 35
  • 49
Alderath
  • 3,761
  • 1
  • 25
  • 43
1

Simple yet effective

 for (ConfigDataModel.VisaTypesBean.AddedBean visatype : visaTypesBeans) {
                            if (visatype.getId() == 24) {

                            }
Kaustubh Bhagwat
  • 2,773
  • 1
  • 14
  • 20
1

Either one will do. Depending on JVM, the second may be a few clock-cycles faster, but it will be an immeasurable or insignificant difference. Beware of these types of sub-optimizations. Unless you are building a real-time system, where every CPU tick counts, they just add complexity and more sources for errors.

I would suggest using the iterator construct (as has already been suggested)

for (Flower flower: flowers) { ...

It's clear, flexible and predicatble.

geisterfurz007
  • 5,292
  • 5
  • 33
  • 54
pap
  • 27,064
  • 6
  • 41
  • 46
0

To avoid all this numbering and iterators and checkings in writing the code use the following simple most readable code that has its performance to maximum. Why this has maximum performance (details are coming up)

for (Object object : aCollection) { 
// Do something here
}

If the index is needed then: To choose between the above two forms: The second is the better because you're using a local variable for checking up. When the method is exited the variable is gone to the trash ou of the stack.

GingerHead
  • 8,130
  • 15
  • 59
  • 93
0

My approach is bit different on this problem. For me, it really doesn't matter which method you choose. the reason is the "performance improvement" you will get in the best optimized method will be ~50ms for 2,500,000 iteration!! (as per @David's post). And obviously this improvement is not something like you would like to waste your valuable time in finding optimized solution.

(But still, as per OP's original question, I would also like to suggest the last approach.)

I know the answer is bit weird and un-common, but this is the reality.

Nirmit Shah
  • 758
  • 4
  • 10
-1
String d = JOptionPane.showInputDialog("enter start");
int s = Integer.parseInt(d);
String h = JOptionPane.showInputDialog("enter the end");
int z = Integer.parseInt(h);
for (int a = 1 ; a<10 ; a++) { 
    if (a%2 == 0 ) {
        JOptionPane.showMessageDialog(null, a);
        System.out.print(a);
    }
}    
-1

go for the first one only as both are same, but creating one more redundent int variable in second code snippet.

So go for the first code snippet

for (int i = 0; i < flowers.size(); i++) {
 ...
} 
developer
  • 9,116
  • 29
  • 91
  • 150