Of course! The for-each loop, also known as the enhanced for loop, is a core feature in Java for iterating over collections and arrays. It's a more concise and readable way to loop than the traditional for loop when you just need to access every element.

Here's a complete guide, from basic syntax to advanced examples and best practices.
Basic Syntax
The syntax is simple and declarative: you declare a variable that will hold each element from the collection, and the loop automatically iterates through the entire collection.
for (Type variable : collection) {
// Code to execute for each element
}
Type: The data type of the elements in the collection (e.g.,String,Integer,Object).variable: A new variable that will hold the current element in each iteration. Its type must be compatible with the collection's element type.collection: The array orIterableobject (likeList,Set, etc.) you want to loop over.
How It Works: The Magic Behind the Scenes
The for-each loop is essentially syntactic sugar. The Java compiler automatically converts it into a standard for loop using an Iterator.
Your code:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
for (String name : names) {
System.out.println(name);
}
What the compiler sees (roughly):
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Get an iterator from the list
Iterator<String> iterator = names.iterator();
// Loop as long as there are more elements
while (iterator.hasNext()) {
// Get the next element and assign it to the variable
String name = iterator.next();
System.out.println(name);
}
This is why the for-each loop can only be used with objects that implement the java.lang.Iterable interface (which includes all collection classes like List, Set, etc.) or with arrays.
Examples with Different Data Types
a) Iterating over an Array
public class ArrayExample {
public static void main(String[] args) {
String[] fruits = { "Apple", "Banana", "Cherry" };
System.out.println("Fruits:");
for (String fruit : fruits) {
System.out.println(fruit);
}
// With primitive types
int[] numbers = { 10, 20, 30, 40, 50 };
System.out.println("\nNumbers:");
for (int number : numbers) {
System.out.println(number);
}
}
}
Output:
Fruits:
Apple
Banana
Cherry
Numbers:
10
20
30
40
50
b) Iterating over a List
This is the most common use case.

import java.util.Arrays;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// Create a List
List<Integer> scores = Arrays.asList(95, 88, 76, 100, 54);
System.out.println("Student Scores:");
for (Integer score : scores) {
System.out.println("Score: " + score);
}
}
}
Output:
Student Scores:
Score: 95
Score: 88
Score: 76
Score: 100
Score: 54
c) Iterating over a Set
Since a Set guarantees uniqueness, the for-each loop is perfect for processing unique items. The order of iteration is not guaranteed (unless it's a LinkedHashSet or TreeSet).
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
Set<String> uniqueTags = new HashSet<>();
uniqueTags.add("java");
uniqueTags.add("programming");
uniqueTags.add("tutorial");
uniqueTags.add("java"); // Duplicate will be ignored
System.out.println("Unique Tags:");
for (String tag : uniqueTags) {
System.out.println("- " + tag);
}
}
}
(Possible Output - order may vary)
Unique Tags:
- java
- tutorial
- programming
When to Use for-each vs. The Traditional for Loop
The for-each loop is great, but it's not a one-size-fits-all solution. Here’s a comparison to help you choose.
| Feature | for-each Loop |
Traditional for Loop |
|---|---|---|
| Readability | Excellent. Very clear and concise. | Good. More verbose, but all loop variables are in one place. |
| Modification | Cannot modify the collection while iterating (will throw ConcurrentModificationException). |
Can modify the collection if you use the iterator's remove() method. |
| Index Access | No. You cannot get the index of the current element. | Yes. You have direct access to the index (i). |
| Bidirectional | No. You can only iterate forward. | Yes. You can loop forwards (i++) and backwards (i--). |
| Iteration Subset | No. You must iterate over the entire collection. | Yes. You can loop over a specific range (for (int i = 2; i < 5; ...)). |
Important Limitations and Caveats
a) The ConcurrentModificationException
You cannot add or remove elements from a collection while iterating over it with a for-each loop. This is because the loop uses an iterator, and modifying the collection directly invalidates the iterator.
import java.util.ArrayList;
import java.util.List;
public class ConcurrentModificationExample {
public static void main(String[] args) {
List<String> names = new ArrayList<>(Arrays.asList("Alice", "Bob", "Charlie"));
// This will throw a ConcurrentModificationException!
for (String name : names) {
if (name.equals("Bob")) {
names.remove(name); // DO NOT DO THIS
}
}
}
}
Solutions:
- Use the traditional
forloop: This gives you more control.for (int i = 0; i < names.size(); i++) { if (names.get(i).equals("Bob")) { names.remove(i); i--; // Important: decrement the index because the list shifted } } - Use the iterator's
remove()method: This is the safest and most correct way.Iterator<String> iterator = names.iterator(); while (iterator.hasNext()) { String name = iterator.next(); if (name.equals("Bob")) { iterator.remove(); // Safe removal } }
b) Cannot Get the Index
If you need the index of the current element (e.g., to print "Item 1: Apple"), the for-each loop is not the right tool. Use the traditional for loop or an IntStream with forEach.
// Traditional for loop (best for index)
List<String> items = Arrays.asList("Apple", "Banana", "Cherry");
for (int i = 0; i < items.size(); i++) {
System.out.println("Item " + (i + 1) + ": " + items.get(i));
}
// Using IntStream (Java 8+)
IntStream.range(0, items.size()).forEach(i -> {
System.out.println("Item " + (i + 1) + ": " + items.get(i));
});
Java 8+: The forEach() Method with Lambdas
For those using Java 8 or later, the forEach() method is another powerful and often preferred way to iterate, especially when combined with lambda expressions or method references.
forEach() on a Collection
import java.util.Arrays;
import java.util.List;
public class ForEachMethodExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Using a lambda expression
System.out.println("Using Lambda:");
names.forEach(name -> System.out.println(name));
// Using a method reference (more concise)
System.out.println("\nUsing Method Reference:");
names.forEach(System.out::println);
}
}
forEach() on a Stream
The forEach method is also a terminal operation on streams, which is very powerful for data processing pipelines.
import java.util.Arrays;
import java.util.List;
public class StreamForEachExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Filter even numbers and print them
numbers.stream()
.filter(n -> n % 2 == 0) // Keep only even numbers
.forEach(System.out::println); // Print each one
}
}
Output:
2
4
6
8
10
Summary: Which One Should You Use?
| Your Goal | Recommended Loop |
| :--- | :--- | :--- |
| Iterate through all elements of a collection or array and don't need the index. | for-each loop. It's the most readable and idiomatic choice. |
| Need the index of the current element. | Traditional for loop. |
| Need to add or remove elements from the collection while iterating. | Traditional for loop (with caution) or use the iterator's remove() method. |
| Need to iterate backwards or over a specific range. | Traditional for loop. |
| Are working with a Stream for complex data processing (filter, map, reduce). | stream().forEach(...). |
