I keep running into moments where the enhanced for loop in Java 5 turns a messy block into something I can read in one sip of coffee.
J2SE 5.0 brought shiny stuff like generics and annotations, yet the quiet hero for day to day code is the foreach style loop. The syntax is short, the intent is clear, and it works with arrays and anything that implements Iterable. If you have been doing the old dance with index variables or juggling an Iterator, this will feel like switching from a stick shift to an automatic in rush hour. Before Java 5 most of my loops looked like this:
// list
for (int i = 0; i < list.size(); i++) {
Thing t = (Thing) list.get(i); // casts everywhere before generics
t.process();
}
// iterator
for (Iterator it = list.iterator(); it.hasNext(); ) {
Thing t = (Thing) it.next();
t.process();
}
// array
for (int i = 0; i < arr.length; i++) {
int n = arr[i];
sum += n;
}Now the loop reads like the intent in my head. One element at a time, no ceremony, no noise. With the enhanced for loop the same code becomes:
for (Thing t : list) {
t.process();
}
for (int n : arr) {
sum += n;
}The rule of thumb is simple. If you want to iterate without caring about the position, use the new loop. It works for arrays and for any collection that exposes an Iterator. Under the covers it calls that iterator for you, so you get the same behavior with nicer clothes. With generics the types read well too. No more raw casts sprinkled all over the place. For example, a List<String> loops like this:
List<String> names = new ArrayList<String>();
names.add("Ada");
names.add("Linus");
names.add("Grace");
for (String name : names) {
System.out.println(name.toUpperCase());
}Maps deserve a quick note because they are not directly iterable by entry unless you ask them to be. If you want keys, loop over map.keySet(). If you want values, map.values(). If you want both in a tight loop, use entrySet so you do not trigger an extra lookup for each value. With generics this reads clean and avoids casts:
Map<String, Integer> ages = new HashMap<String, Integer>();
ages.put("Alice", 31);
ages.put("Bob", 28);
// keys
for (String user : ages.keySet()) {
System.out.println(user);
}
// values
for (Integer age : ages.values()) {
total += age;
}
// entries
for (Map.Entry<String, Integer> e : ages.entrySet()) {
System.out.println(e.getKey() + " => " + e.getValue());
}There are trade offs. The new loop is not a match when you need the index. If you must peek at neighbors, write into a specific position, or zip two lists by index, keep the classic loop. You also do not get removal for free. If you call remove on the collection while inside the foreach loop, you will meet a ConcurrentModificationException. The safe route for removals during traversal is to reach for the iterator and call remove() on it:
for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
Thing t = it.next();
if (t.isStale()) {
it.remove(); // safe removal during iteration
}
}One more spot where the old pattern stays handy is when you want to write back into the same array or list at a position. You can read with foreach, but you cannot set by index through it. In that case the plain loop still wins clarity:
for (int i = 0; i < scores.size(); i++) {
scores.set(i, scores.get(i) + bonus);
}What about performance. For arrays the foreach loop compiles into the same kind of iteration you would write by hand. For collections it is the iterator path you already use. The gain is not in microseconds but in readability and fewer silly mistakes. Shorter loops mean fewer variables, fewer casts, and fewer off by one bugs. When I revisit code after a week, the foreach version explains itself with less brain power. That is the real win for me. I can skim a file and spot the business rules without tripping over scaffolding.
Quick tip if you are introducing this to a codebase that still has raw types. Add generics as you touch a class. The compiler will guide you. Then switch loops where it makes sense. It lands well in reviews because the diff gets smaller and the intent gets bolder. And if you adopt enums or autoboxing in the same pass, the code starts to feel modern without a giant rewrite.
Use foreach for clear read only traversal of arrays and collections, keep the classic loop when you need the index or safe in place edits.
For maps prefer entrySet() in hot loops, and reach for the iterator when you need removal during the walk.