JavaRush/Java Blog/Random EN/Coffee break #137. For loop or Foreach - which one is fas...

Coffee break #137. For loop or Foreach - which one is faster in Java? 8 Efficient Ways to Loop Through Each Entry in a Java Map

Published in the Random EN group
members

For loop or Foreach - which one is faster in Java?

Source: Medium When I was looking for a job a couple of years ago, one of the questions I was asked in an interview was whether we should iterate over an ArrayList using for or forEach ? Coffee break #137.  For loop or Foreach - which one is faster in Java?  8 Efficient Ways to Loop Through Each Entry in a Java Map - 1The debate about the difference in preferences between forEach and for has been around for a long time. I was under the impression that forEach is faster. But in the end I realized that I was wrong. FYI, the forEach loop (or improved for loop ) introduced in Java 1.5 eliminates the clutter and possibility of error by hiding the iterator or index variable entirely. I believe the only practical difference between for and forEach is that in the case of indexed objects, we don't have access to index.
for(int i = 0; i < mylist.length; i++) {
 if(i < 5) {
 //do something
 } else {
 //do other stuff
 }
}
However, we can create a separate index variable of type int using forEach . For example:
int index = -1;
for(int myint : mylist) {
 index++;
 if(index < 5) {
 //do something
 } else {
 //do other stuff
 }
}
Let's write a simple class that has a foreachTest() method that iterates through a list using forEach .
import java.util.List;

public class ForEachTest {
	List<Integer> intList;

    public void foreachTest(){
        for(Integer i : intList){

        }
    }
}
When we compile this class, the compiler internally converts the code into an iterator implementation. I decompiled the compiled code by running javap -verbose IterateListTest .
public void foreachTest();
   descriptor: ()V
   flags: ACC_PUBLIC
   Code:
     stack=1, locals=3, args_size=1
        0: aload_0
        1: getfield      #19                 // Field intList:Ljava/util/List;
        4: invokeinterface #21,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        9: astore_2
       10: goto          23
       13: aload_2
       14: invokeinterface #27,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
       19: checkcast     #33                 // class java/lang/Integer
       22: astore_1
       23: aload_2
       24: invokeinterface #35,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
       29: ifne          13
       32: return
     LineNumberTable:
       line 9: 0
       line 12: 32
     LocalVariableTable:
       Start  Length  Slot  Name   Signature
           0      33     0  this   Lcom/greekykhs/springboot/ForEachTest;
     StackMapTable: number_of_entries = 2
       frame_type = 255 /* full_frame */
         offset_delta = 13
         locals = [ class com/greekykhs/springboot/ForEachTest, top, class java/util/Iterator ]
         stack = []
       frame_type = 9 /* same */
From the bytecode above we see:
  1. The getfield command is used to obtain integer variables.

  2. Call List.iterator to get an iterator instance.

  3. Call iterator.hasNext . If it returns true, the iterator.next method should be called .

Let's run a performance test. In the main IterateListTest method , I created a list and iterated through it using for and forEach loops .
import java.util.ArrayList;
import java.util.List;

public class IterateListTest {
	public static void main(String[] args) {
		List<Integer> mylist = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            mylist.add(i);
        }

        long forLoopStartTime = System.currentTimeMillis();
        for (int i = 0; i < mylist.size(); i++) {mylist.get(i);}

        long forLoopTraversalCost =System.currentTimeMillis()-forLoopStartTime;
        System.out.println("for loop traversal cost for ArrayList= "+ forLoopTraversalCost);

        long forEachStartTime = System.currentTimeMillis();
        for (Integer integer : mylist) {}

        long forEachTraversalCost =System.currentTimeMillis()-forEachStartTime;
        System.out.println("foreach traversal cost for ArrayList= "+ forEachTraversalCost);
	}
}
And here is the result: Coffee break #137.  For loop or Foreach - which one is faster in Java?  8 Efficient Ways to Iterate Through Each Entry in a Java Map - 2As we can see, the performance of the for loop is better than the forEach loop . If you use LinkedList instead of ArrayList , you can see that forEach performance is better for LinkedList . ArrayList internally uses arrays to store elements. Since arrays are contiguous regions of memory, the time complexity is O(1). This is because data is retrieved through indexes. LinkedList uses a doubly linked list. When we use a for loop to implement traversal, it starts from the head node of the linked list each time, so the time complexity is O(n*n).

8 Efficient Ways to Loop Through Each Entry in a Java Map

Source: Medium Last week, an intern asked me how to iterate a Java Map. I replied that since it is very simple, the answer to this question is always on Google. After some time, she sent me the address of the page on StackOverflow, and it turned out that a huge number of people were paying attention to this problem. Therefore, I decided to dwell on the issue of iteration and share several ways to do it with you. Coffee break #137.  For loop or Foreach - which one is faster in Java?  8 Efficient Ways to Iterate Through Each Entry in a Java Map - 3

1. Using iterator and Map.Entry

@Test
public void test1_UsingWhileAndMapEntry(){
    long i = 0;
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<Integer, Integer> pair = it.next();
        i += pair.getKey() + pair.getValue();
    }
    System.out.println(i);
}

2. Using foreach and Map.Entry

@Test
public void test2_UsingForEachAndMapEntry(){
    long i = 0;
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        i += pair.getKey() + pair.getValue();
    }
    System.out.println(i);
}

3. Using foreach from Java 8

@Test
public void test3_UsingForEachAndJava8(){
    final long[] i = {0};
    map.forEach((k, v) -> i[0] += k + v);
    System.out.println(i[0]);
}

4. Using keySet and foreach

@Test
public void test4_UsingKeySetAndForEach(){
    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
    System.out.println(i);
}

5. Using keySet and iterator

@Test
public void test5_UsingKeySetAndIterator(){
    long i = 0;
    Iterator<Integer> it = map.keySet().iterator();
    while (it.hasNext()) {
        Integer key = it.next();
        i += key + map.get(key);
    }
    System.out.println(i);
}

6. Using for and Map.Entry

@Test
public void test6_UsingForAndIterator(){
    long i = 0;
    for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) {
        Map.Entry<Integer, Integer> entry = entries.next();
        i += entry.getKey() + entry.getValue();
    }
    System.out.println(i);
}

7. Using Java 8 Stream API

@Test
public void test7_UsingJava8StreamApi(){
    System. out .println(map.entrySet().stream().mapToLong(e -> e.getKey() + e.getValue()).sum());
}

8. Parallel use of Java 8 Stream API

@Test
public void test8_UsingJava8StreamApiParallel(){
    System. out .println(map.entrySet().parallelStream().mapToLong(e -> e.getKey() + e.getValue()).sum());
}

Comparison of each method in terms of speed:

public final static Integer SIZE = 1000000;
public Map<Integer, Integer> map = toMap();
public Map<Integer, Integer> toMap(){
    map = new HashMap<>(SIZE);
    for (int i = 0; i < SIZE; i++) {
        map.put(i, i);
    }
    return map;
}
We get: Coffee break #137.  For loop or Foreach - which one is faster in Java?  8 Efficient Ways to Loop Through Each Entry in a Java Map - 4Coffee break #137.  For loop or Foreach - which one is faster in Java?  8 Efficient Ways to Iterate Through Each Entry in a Java Map - 5Coffee break #137.  For loop or Foreach - which one is faster in Java?  8 Efficient Ways to Iterate Through Each Entry in a Java Map - 6

Conclusion

From comparing the data, we learned that method 6 takes the most time and method 8 takes the most time when the number is small, but takes the least time when the number is significant because method 8 is executed simultaneously. The interesting thing is that the test execution order is always for -> while -> foreach/stream and I don't know why :(
Comments
  • Popular
  • New
  • Old
You must be signed in to leave a comment
This page doesn't have any comments yet