In Java, there are several strategies for looping through a list, such as for-each, stream, and more. In this article, we'll explore the performance of these loop strategies as applied to ArrayList, LinkedList, and Vector.
Traditional For Loop
The first test uses the traditional for loop, a construct present in almost all programming languages:
long sum = 0;
for (int i = 0; i < numberOfElements; i++) {
sum += list.get(i);
}Below is a comparison of the performance for short lists (up to 100 elements) and medium lists (100 to 1,000 elements):
Facts:
- ArrayList has linear performance efficiency.
- Vector also has linear performance efficiency but is slower than ArrayList because Vector is a synchronized list, which adds overhead to each operation.
- LinkedList naturally shows low performance when accessing elements by index. However, for short lists, its performance is better than Vector.
- As the list size increases, LinkedList performance degrades significantly. For example, processing 100k elements took 4 seconds, while ArrayList processed the same amount in less than one millisecond.
For-Each Loop
The second comparison uses the for-each statement to iterate over the items:
long sum = 0;
for (int i : list) {
sum += list.get(i);
}Below is a comparison of the performance for short lists (up to 100 elements) and medium lists (100 to 1,000 elements):
Facts:
- ArrayList and Vector have linear performance efficiency.
- LinkedList naturally shows low performance when accessing elements by index. However, for short lists, its performance is better than Vector.
- In summary, follow the same pattern as the traditional for statement.
Iterator
The next way to loop through a list is by using an iterator:
var iterator = list.iterator();
while (iterator.hasNext()) {
sum += list.get(iterator.next());
}Below is a comparison of the performance for short lists (up to 100 elements) and medium lists (100 to 1,000 elements):
Since the iterator works in the same way as the for-each loop, the performance is nearly identical.
Stream
This is likely the most commonly used loop mechanism in modern programs:
long sum = list.stream()
.map(Integer::longValue)
.reduce(0L, Long::sum);Below is a comparison of the performance for short lists (up to 100 elements) and medium lists (100 to 1,000 elements):
Facts:
- The good news is that with the stream implementation, all lists exhibit similar performance.
- The differences shown in the charts are minimal, with some variations due to processor overhead.
Parallel Stream
A variant of the stream is the parallel stream, which internally creates threads to execute stream operations:
long sum = list.parallelStream()
.map(Integer::longValue)
.reduce(0L, Long::sum);Below is a comparison of the performance for short lists (up to 100 elements) and medium lists (100 to 1,000 elements):
Facts:
- Similar to the regular stream, the parallel stream exhibits similar performance regardless of the list used.
- The execution performance is not linear; since it creates threads internally, the amount of data processed is significant.
ArrayList
ArrayList performs better with for and for-each statements. While streams have slightly worse performance, it is still efficient in absolute terms, as it can process 100k elements in less than one millisecond.
LinkedList
LinkedList has exponential complexity when using for, for-each, and iterator loops. The good news is that its performance with streams and parallel streams is linear.
Vector
Vector has better performance with streams. However, using iterators with Vector results in the worst performance.