Java For vs Enhanced For: Choosing the Right Loop
java for vs enhanced for: Compare Java's traditional for loop and enhanced for loop: syntax, use cases, performance, and when each is the right choice.
The java for vs enhanced for decision comes up whenever you need to iterate over a collection or array. The traditional for loop gives you explicit control over the index, while the enhanced for loop (also called for-each) hides that control. The right choice depends on whether you need the index, whether you are modifying the structure, and what performance characteristics matter.
Basic Syntax of For and Enhanced For
The traditional for loop has three parts: initialization, condition, and update. You control the loop variable explicitly.
int[] numbers = {1, 2, 3, 4}; for (int i = 0; i < numbers.length; i++) { System.out.println(numbers[i]); }
The enhanced for loop removes the index variable entirely. It works with arrays and any object that implements Iterable.
int[] numbers = {1, 2, 3, 4}; for (int number : numbers) { System.out.println(number); }
The enhanced for loop is syntactic sugar. The compiler translates it into a traditional for loop using an iterator for collections, or a simple index loop for arrays. This means the two forms are functionally equivalent for simple iteration.
When the Traditional For Loop Is Necessary
The traditional for loop is required when you need the index value inside the loop body. Common cases include:
- Accessing an element at a specific position relative to the current index.
- Comparing the current element with the previous or next element.
- Writing to an array at a specific index.
- Iterating over multiple arrays in parallel using the same index.
String[] names = {"Alice", "Bob", "Charlie"}; for (int i = 0; i < names.length; i++) { System.out.println(i + ": " + names[i]); }
You also need the traditional loop when you want to skip elements or iterate in reverse order. The enhanced for loop always moves forward from the first element to the last, with no way to skip or rewind.
for (int i = names.length - 1; i >= 0; i--) { System.out.println(names[i]); }
Another case is when you need to modify the array elements themselves. The enhanced for loop gives you a copy of the value for primitives, and a reference to the object for reference types, but you cannot replace the element in the original array.
When the Enhanced For Loop Is the Better Choice
The enhanced for loop is the better choice when you only need to read each element in order. It is shorter, less error-prone, and clearly communicates intent. You do not have to manage the index, and you avoid off-by-one errors.
List<String> items = List.of("apple", "banana", "cherry"); for (String item : items) { System.out.println(item); }
For collections, the enhanced for loop uses an iterator internally. That means it works with any Iterable implementation, including List, Set, Queue, and custom collections. The traditional for loop with an index only works with arrays and List implementations that support random access, such as ArrayList. For a LinkedList, using get(i) inside a traditional loop is O(n) per access, making the loop O(n^2). The enhanced for loop avoids that by using the iterator directly.
Performance: What the Bytecode Reveals
For arrays, both loops compile to nearly identical bytecode. The enhanced for loop becomes an index-based loop, so there is no performance penalty. For collections, the enhanced for loop uses an iterator, while a traditional for loop using get(i) may be slower for non-random-access lists.
Consider this code:
List<String> list = new LinkedList<>(); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); }
Each get(i) traverses the list from the beginning, resulting in quadratic time. The enhanced for loop uses the list's iterator, which visits each node once, giving linear time.
for (String s : list) { System.out.println(s); }
There is no inherent performance advantage to the traditional loop for simple iteration. The enhanced for loop is at least as fast for arrays and usually faster for LinkedList. The only performance concern is if you need to avoid iterator allocation, but the JVM often eliminates that allocation through escape analysis.
Common Pitfalls with Both Loops
One common mistake is trying to remove elements from a collection inside an enhanced for loop. This throws a ConcurrentModificationException because the iterator detects structural modification.
List<String> list = new ArrayList<>(List.of("a", "b", "c")); for (String s : list) { if (s.equals("b")) { list.remove(s); // throws ConcurrentModificationException } }
To remove elements safely, use an explicit iterator and its remove method, or use removeIf on the collection.
list.removeIf(s -> s.equals("b"));
Another pitfall is assuming the enhanced for loop gives you access to the index. It does not. If you need the index, you must either use a traditional loop or maintain a separate counter variable.
int index = 0; for (String s : list) { System.out.println(index + ": " + s); index++; }
This works but is less clean than a traditional loop when the index is central to the logic.
Modifying a Collection While Iterating
Modifying a collection during iteration is a frequent source of bugs. The enhanced for loop uses a fail-fast iterator, which throws an exception if the collection is modified after the iterator is created. This is a safety feature, but it can be surprising.
If you need to add elements during iteration, you cannot use the enhanced for loop directly. You can use a traditional loop with an index for an ArrayList, but the size changes and you must adjust the index carefully. A better approach is to collect changes and apply them after iteration.
List<String> toAdd = new ArrayList<>(); for (String s : list) { if (s.startsWith("a")) { toAdd.add(s + "-new"); } } list.addAll(toAdd);
For concurrent modifications, use CopyOnWriteArrayList or other concurrent collections that allow safe iteration while modifying.
Choosing Based on Your Data Structure
The decision between traditional and enhanced for loops often comes down to the data structure you are iterating over. For arrays and ArrayList, both loops are equally efficient, and the choice is based on whether you need the index. For LinkedList, the enhanced for loop is clearly better because it avoids repeated traversal. For sets and queues, the enhanced for loop is the only practical choice because they do not support index-based access.
If you are writing generic code that works with any Iterable, the enhanced for loop is the only option that works without knowing the concrete type. This is especially important when writing library code or methods that accept Collection or Iterable as parameters.
public void printAll(Iterable<String> items) { for (String item : items) { System.out.println(item); } }
The traditional for loop with an index is only appropriate when you have a concrete array or a List with random access. It is also needed when you must manipulate the index, such as iterating in reverse or skipping elements. For most iteration tasks, the enhanced for loop is the safer and more readable choice.