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 ? The 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:
-
The getfield command is used to obtain integer variables.
-
Call List.iterator to get an iterator instance.
-
Call iterator.hasNext . If it returns true, the iterator.next method should be called .
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: As 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.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: