What’s New ?

The Top 10 favtutor Features You Might Have Overlooked

Read More

For-Each Loop in Java (with Examples)

  • Dec 05, 2023
  • 8 Minutes Read
For-Each Loop in Java (with Examples)

Loops are essential for iterating over collections and arrays in Java programming. Java introduced the forEach loop, sometimes known as an enhanced for loop, to simplify the iteration process, whereas classic for loops has been widely used. In this article, we will 

What is forEach Loop in Java?

The forEach loop, introduced in Java 5, provides a simplified syntax for iterating over arrays and collections. The forEach loop is preferred because of its readability and ability to provide a more compact syntax.

The syntax is straightforward:

for (element_type element : iterable_collection) {
    // code to be executed for each element
}

 

Here, the element type is the type of elements in the collection, and iterable_collection is the array or collection to be iterated. The loop traverses each element of the collection, making it a powerful tool for streamlined iteration.

The foreach loop is characterized by its simplicity and ease of use. It eliminates the need for manual management of loop variables and simplifies the code, making it more readable. This is especially beneficial when dealing with complex data structures and nested loops, where traditional loops might introduce verbosity.

In contrast to the traditional for loop, which requires manual control over the loop variable and iteration conditions, the for-each loop abstracts away these details. It automatically iterates over the elements of an iterable object, enhancing code clarity. Let's compare the two approaches with a practical example!

Consider the following traditional for loop:

// Traditional for loop
int[] numbers = {1, 2, 3, 4, 5};

for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

 

Now, let's achieve the same result using the forEach loop: 

// foreach loop
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
    System.out.println(number);
}

 

In this example, the foreach loop eliminates the need for maintaining an index variable, resulting in cleaner and more concise code.

forEach with Arrays and Collections

Let’s see the it's working with Arrays and Collections.

The foreach loop brings elegance to iterating over arrays, offering a more readable alternative to the traditional for loop. Let's explore how the forEach loop simplifies array iteration:

public class ForEachArrayExample {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};

        // Traditional for loop
        System.out.println("Traditional for loop:");
        for (int i = 0; i < numbers.length; i++) {
            System.out.println(numbers[i]);
        }

        // foreach loop
        System.out.println("\nforeach loop:");
        for (int number : numbers) {
            System.out.println(number);
        }
    }
}

 

Output:

Traditional for loop:
1
2
3
4
5

foreach loop:
1
2
3
4
5

 

The foreach loop's concise syntax simplifies array traversal. The loop variable (number in this case) automatically takes on the value of each element in the array, eliminating the need for index management.

The foreach loop seamlessly integrates with Java's collections, providing an elegant solution for iterating over elements. Let's explore forEach with different collection types:

import java.util.*;

public class ForEachCollectionExample {
    public static void main(String[] args) {
        // List
        List<String> itemList = Arrays.asList("Widget", "Gadget", "Tool", "Device");

        System.out.println("List iteration using foreach:");
        for (String item : itemList) {
            System.out.println("Processing item: " + item);
        }

        // Set
        Set<Integer> quantitySet = new HashSet<>(Arrays.asList(10, 20, 30, 40, 50));

        System.out.println("\nSet iteration using foreach:");
        for (int quantity : quantitySet) {
            System.out.println("Updating quantity: " + quantity);
        }

        // Map
        Map<String, Integer> inventoryMap = new HashMap<>();
        inventoryMap.put("Engine", 28);
        inventoryMap.put("Machine", 35);
        inventoryMap.put("Component", 22);

        System.out.println("\nMap iteration using foreach:");
        for (Map.Entry<String, Integer> entry : inventoryMap.entrySet()) {
            System.out.println("Item: " + entry.getKey() + ", Quantity: " + entry.getValue());
        }
    }
}

 

Output:

List iteration using foreach:
Processing item: Widget
Processing item: Gadget
Processing item: Tool
Processing item: Device

Set iteration using foreach:
Updating quantity: 40
Updating quantity: 10
Updating quantity: 50
Updating quantity: 20
Updating quantity: 30

Map iteration using foreach:
Item: Engine, Quantity: 28
Item: Machine, Quantity: 35
Item: Component, Quantity: 22

 

In this example, we showcase how the forEach loop seamlessly works with different types of collections, providing a clean and concise syntax for iteration.

Iterating over Custom Objects using forEach

Now, let’s look at how we can iterate over custom objects.

1) Iterable Interface

The true power of the foreach loop shines when working with custom objects. To enable forEach loop functionality for user-defined classes, the class must implement the Iterable interface. The Iterable interface requires the implementation of the iterator() method, which returns an iterator object.

Let's see an example:

import java.util.Iterator;

class CustomIterable implements Iterable<String> {
    private String[] elements;

    public CustomIterable(String[] elements) {
        this.elements = elements;
    }

    @Override
    public Iterator<String> iterator() {
        return new CustomIterator();
    }

    private class CustomIterator implements Iterator<String> {
        private int index = 0;

        @Override
        public boolean hasNext() {
            return index < elements.length;
        }

        @Override
        public String next() {
            return elements[index++];
        }
    }
}

 

In this example, the CustomIterable class implements the Iterable interface, providing an iterator through the CustomIterator inner class.

2) Custom Objects with Iterable Implementation

Now, let's use our custom iterable object with the foreach loop:

import java.util.Iterator;

public class ForEachCustomObjectExample {
    public static void main(String[] args) {
        String[] projectNames = {"Project Alpha", "Project Beta", "Project Gamma", "Project Delta"};
        CustomIterable customIterable = new CustomIterable(projectNames);

        System.out.println("Custom object iteration using foreach:");
        for (String project : customIterable) {
            System.out.println("Working on: " + project);
        }
    }
}

class CustomIterable implements Iterable<String> {
    private String[] elements;

    public CustomIterable(String[] elements) {
        this.elements = elements;
    }

    @Override
    public Iterator<String> iterator() {
        return new CustomIterator();
    }

    private class CustomIterator implements Iterator<String> {
        private int index = 0;

        @Override
        public boolean hasNext() {
            return index < elements.length;
        }

        @Override
        public String next() {
            return elements[index++];
        }
    }
}

 

Output:

Custom object iteration using foreach:
Working on: Project Alpha
Working on: Project Beta
Working on: Project Gamma
Working on: Project Delta

 

By implementing the Iterable interface, our custom object seamlessly integrates with the for each loop, providing a clean and expressive way to iterate over its elements.

Limitations of foreach Loop

Despite the simplification of iteration by the foreach loop, it introduces a significant limitation – it lacks support for the modification of elements during the iteration process. Attempting such modifications within the loop context may lead to encountering a ConcurrentModificationException.

Let's illustrate this limitation through an example: 

import java.util.ArrayList;
import java.util.List;

public class ForEachModificationExample {
    public static void main(String[] args) {
        List<String> projectTasks = new ArrayList<>();
        projectTasks.add("Task A");
        projectTasks.add("Task B");
        projectTasks.add("Task C");

        // Incorrect approach: Modifying elements during iteration
        for (String task : projectTasks) {
            if (task.equals("Task B")) {
                projectTasks.remove(task); // This will throw ConcurrentModificationException
            }
        }
    }
}

 

To avoid this exception, modifications should be done outside the forEach loop or by using an explicit iterator:

// Correct approach: Modifying elements outside the foreach loop
projectTasks.removeIf(task -> task.equals("Task B"));

// or

// Utilizing an explicit iterator
Iterator<String> iterator = projectTasks.iterator();
while (iterator.hasNext()) {
    String task = iterator.next();
    if (task.equals("Task B")) {
        iterator.remove(); // Correct: Modifying the list through the iterator
    }
}

 

These examples highlight the necessity of avoiding in-loop modifications to prevent encountering the ConcurrentModificationException, showcasing alternate approaches that ensure safe modification of the list's elements. 

One more drawback of the forEach loop is the absence of direct index information. In scenarios where access to the index is necessary, the traditional for loop might be more appropriate.

However, there are alternative approaches, such as maintaining a separate variable to track the index:

int index = 0;
for (String subject : subList) {
    System.out.println("Index: " + index + ", Subject: " + subject);
    index++;
}

 

Use Cases and Best Practices

Following are some use cases of forEach loop:

1) Simplifying Code

One of the primary use cases for the foreach loop is to simplify code, especially when dealing with collections or arrays. Consider the following example, where we have a list of numbers, and we want to calculate the sum using a traditional for loop versus a forEach loop:

import java.util.ArrayList;
import java.util.List;

public class ForEachUseCaseExample {
    public static void main(String[] args) {
        List<Integer> numbersList = List.of(1, 2, 3, 4, 5);

        // Traditional for loop
        int sumTraditional = 0;
        for (int i = 0; i < numbersList.size(); i++) {
            sumTraditional += numbersList.get(i);
        }

        // foreach loop
        int sumForeach = 0;
        for (int number : numbersList) {
            sumForeach += number;
        }

        System.out.println("Sum using traditional for loop: " + sumTraditional);
        System.out.println("Sum using foreach loop: " + sumForeach);
    }
}

 

Output:

Sum using traditional for loop: 15
Sum using foreach loop: 15

 

In this example, both approaches yield the same result, but the forEach loop provides cleaner and more concise code.

2) Performance Considerations

While the foreach loop is generally more readable, it's essential to consider performance implications in certain scenarios. The foreach loop may introduce some overhead compared to traditional loops, especially when dealing with large datasets. However, modern Java implementations have optimized forEach loop performance to a great extent.

When performance is a critical concern, especially in scenarios requiring manual control ever the loop variable or access to the index, developers might opt for traditional loops.

Conclusion

To sum up, the foreach loop in Java is an adaptable tool for iteration that provides readability, simplicity, and interaction with contemporary Java features. As you proceed with your Java programming journey, carefully consider the advantages and disadvantages of the forEach loop to write efficient and maintainable code.

FavTutor - 24x7 Live Coding Help from Expert Tutors!

About The Author
Nihal Mahansaria
As a computer science student with a passion for technology and a drive to learn, I have developed a diverse set of skills in web development, machine learning, and technical content writing. With experience in multiple front-end and back-end frameworks, including Flask and Python, I am able to create scalable and efficient web applications.