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):

None

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.
None

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):

None

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.
None

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):

None

Since the iterator works in the same way as the for-each loop, the performance is nearly identical.

None

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):

None

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.
None

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):

None

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.
None

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.

None

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.

None

Vector

Vector has better performance with streams. However, using iterators with Vector results in the worst performance.

None