The for-each loop, also called the enhanced for loop, runs a block of code once for each item in an array or a collection, handing you the items one at a time in a variable. You write it as for (String name : names)and read it aloud as “for each name in names”. This page shows it with arrays, lists and maps, when a counting for loop is the better choice, and what the for-each loop cannot do. Every example runs in the page.
public class Main { public static void main(String[] args) { String[] fruits = {"apple", "banana", "cherry"}; for (String fruit : fruits) { System.out.println("I like " + fruit); } }}Press Run and step through it. On the first pass fruit holds "apple", on the second "banana", on the third "cherry", and then the loop ends by itself. The program prints I like apple, I like banana and I like cherry.
The header has three parts:
String fruitdeclares the loop variable. Its type has to fit the items (aStringarray givesStringitems), and you choose its name.- The colon reads as “in”.
fruitsis what you loop over: an array, or any object whose class implementsIterable, which every collection does, fromArrayListtoHashSet.
There is no counter to manage, so the loop cannot step past the end of the array. The Java Language Specification calls this loop the enhanced for statement, the second form of the for statement next to the counting loop. With while and do-while, that makes Java's three loop statements, which the loops lesson teaches from the start.
For-each loop with an ArrayList#
A list works the same way as an array. This loop adds up a list of scores:
import java.util.ArrayList; public class Main { public static void main(String[] args) { ArrayList<Integer> scores = new ArrayList<>(); scores.add(72); scores.add(85); scores.add(90); int total = 0; for (int score : scores) { total = total + score; } System.out.println("Total: " + total); }}It prints Total: 247. The list holds Integer objects while score is a plain int: Java unboxes each value as it comes out of the list. Writing for (Integer score : scores) works too.
Using var in the loop header#
Since Java 10 you can write var in place of the type and let Java work it out from what you loop over. In for (var score : scores), score is an Integer, and over a String[] array, var means String. It saves the most typing on long types, such as the map entries below.
Loop over a Map with for-each#
Writing for (String key : stock) over a map does not compile: javac stops with for-each not applicable to expression type, because a Map is not Iterable. It hands out three views that are: entrySet() for the key and value pairs, keySet() for the keys and values() for the values.
import java.util.Map;import java.util.TreeMap; public class Main { public static void main(String[] args) { Map<String, Integer> stock = new TreeMap<>(); stock.put("pears", 4); stock.put("apples", 12); stock.put("plums", 0); for (Map.Entry<String, Integer> entry : stock.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } for (String fruit : stock.keySet()) { System.out.print(fruit + " "); } System.out.println(); int total = 0; for (int count : stock.values()) { total = total + count; } System.out.println("In stock: " + total); }}Each entry is a Map.Entry, a pair with getKey() and getValue(). With var the first header shrinks to for (var entry : stock.entrySet()). A TreeMap keeps its keys sorted, so the program prints apples: 12, pears: 4 and plums: 0, then the three names on one line, then In stock: 16. A HashMaploops the same way, but in an order that comes from the keys' hash codes, which need not be the order you put them in; a LinkedHashMap keeps that order.
For loop vs for-each loop: which to use#
Use the for-each loop when you need each item and nothing else. Use the counting loop, the one with a counter such as i, when the position matters:
- You need the index, for example to number the items or to compare each one with the one before it.
- You go backwards, or skip items, as an update of
i = i + 2does. - You replace items:
prices[i] = 0;changes the array, and assigning to a for-each variable does not. - You walk two arrays side by side, reading
names[i]andscores[i]together.
for (String name : names)for (int i = 0; i < names.length; i++)names[i] or list.get(i).break).names[i] = ... or list.set(i, ...).Iterable, including sets and the views of a map.get(i).i <= names.length throws ArrayIndexOutOfBoundsException.Key ideaReach for the for-each loop by default, and switch to the counting loop as soon as you need to know where you are.
How to get the index in a for-each loop#
The for-each loop hides the index, so there is none to ask for. When you need a position, keep your own counter, or switch to the counting loop. Both loops below number the same three names:
public class Main { public static void main(String[] args) { String[] podium = {"Ada", "Grace", "Linus"}; int place = 1; for (String name : podium) { System.out.println(place + ". " + name); place++; } for (int i = 0; i < podium.length; i++) { System.out.println("podium[" + i + "] = " + podium[i]); } }}The first loop prints 1. Ada, 2. Grace and 3. Linus. The counter starts at 1 because people count from one, and place++ at the end of the body moves it on for the next pass. The second loop prints podium[0] = Ada and so on, because indexes start at 0. If you catch yourself keeping a counter and also reading podium[place - 1], the counting loop is the clearer choice.
list.indexOf(item) looks like a way to get the position. It searches the list from the start on every call and returns the position of the first equal item, so in [5, 7, 5] both fives report 0. Keep a counter instead.Can a for-each loop change the array?#
No. The loop variable holds a copy of the current item, so assigning a new value to it changes the variable and leaves the array as it was. Step through this and watch name change while names stays the same:
import java.util.Arrays; public class Main { public static void main(String[] args) { String[] names = {"ada", "grace", "linus"}; for (String name : names) { name = name.toUpperCase(); } System.out.println(Arrays.toString(names)); for (int i = 0; i < names.length; i++) { names[i] = names[i].toUpperCase(); } System.out.println(Arrays.toString(names)); }}The first line printed is [ada, grace, linus]. Each pass made a new, uppercase string and stored it in name, and the next pass overwrote it. Java gives no error and no warning for that loop. The counting loop writes through the index, names[i] = ..., so the second line is [ADA, GRACE, LINUS]. On an ArrayList, do the same with list.set(i, ...) in a counting loop, or in one call with list.replaceAll(s -> s.toUpperCase()).
Changing an object through the loop variable does work#
When the items are objects, the loop variable refers to the same object the list holds. Assigning to the variable still leaves the list alone, but changing a field through it changes the object itself:
import java.util.ArrayList; public class Main { public static void main(String[] args) { ArrayList<Book> shelf = new ArrayList<>(); shelf.add(new Book("Dune", 2)); shelf.add(new Book("Emma", 0)); for (Book book : shelf) { book.copies = book.copies + 5; } for (Book book : shelf) { System.out.println(book.title + ": " + book.copies); } }} class Book { String title; int copies; Book(String title, int copies) { this.title = title; this.copies = copies; }}It prints Dune: 7 and Emma: 5. In the memory view, book points at the same Book object as the list slot it came from, so the change is there when the second loop reads the list. Methods follow the same rule with their arguments, as the methods lesson shows under pass by value.
Key ideaAssigning to the loop variable never changes the array or list. Changing a field of the object it refers to does, because the variable and the list point at the same object.
Removing items in a for-each loop: ConcurrentModificationException#
Calling remove on a list while a for-each loop walks it stops the program with a ConcurrentModificationException. Run this one to the end:
import java.util.ArrayList;import java.util.List; public class Main { public static void main(String[] args) { List<String> songs = new ArrayList<>(List.of("intro", "skit", "hit", "outro")); for (String song : songs) { if (song.equals("skit")) { songs.remove(song); } } System.out.println(songs); }}ConcurrentModificationException
The collection changed while a loop was walking through it.
Java stops at the for line with Exception in thread "main" java.util.ConcurrentModificationException, and the last line never runs. A for-each loop walks a list with a hidden iterator, an object that remembers where it is, and the iterator checks that the list has not changed each time it fetches the next item. Removing "skit" changed the list behind its back. Adding inside the loop fails the same way. The name mentions concurrency, but one thread is enough to cause it.
ArrayList documentation says the check is made on a best-effort basis and is only there to catch bugs. Never remove from a list inside a for-each loop over it.Two safe ways: Iterator.remove() and removeIf()#
Write the iterator loop yourself, so you can reach the iterator, and remove through it. Or hand the whole job to removeIf. This program does each on its own copy of the list:
import java.util.ArrayList;import java.util.Iterator;import java.util.List; public class Main { public static void main(String[] args) { List<String> songs = new ArrayList<>(List.of("intro", "skit", "hit", "skit", "outro")); List<String> copy = new ArrayList<>(songs); Iterator<String> it = songs.iterator(); while (it.hasNext()) { String song = it.next(); if (song.equals("skit")) { it.remove(); } } System.out.println(songs); copy.removeIf(song -> song.equals("skit")); System.out.println(copy); }}Both lines print [intro, hit, outro]. it.next() returns the next song, and it.remove() removes the one it just returned while keeping the iterator in step, so nothing is skipped and nothing throws. removeIf, from Java 8, runs that loop for you. You give it the rule as a lambda, a small function written inline: song -> song.equals("skit")reads as “given a song, remove it if it is skit”. When the rule fits on one line, removeIf is the shorter choice.
Nested for-each loops over a 2D array#
A 2D array in Java is an array of arrays, so each item of the outer array is a whole row with the type int[]. The outer loop takes one row at a time, and an inner loop walks that row:
public class Main { public static void main(String[] args) { int[][] seats = { {1, 0, 1}, {0, 0, 1}, {1, 1, 1} }; int taken = 0; for (int[] row : seats) { for (int seat : row) { taken = taken + seat; } } System.out.println(taken + " of 9 seats are taken"); }}row holds one inner array per pass, and seat holds each number in it, nine passes of the inner loop in all. The program prints 6 of 9 seats are taken. Rows of different lengths are fine too, because the inner loop always walks the row it was given.
What the for-each loop does underneath#
The Java Language Specification (section 14.14.2) defines the for-each loop by rewriting it as an ordinary for loop, and the rewrite depends on what you loop over:
- Over an array, Java evaluates the array once, then runs a hidden index from 0 up to
length - 1, and at the start of each pass copies the item at that index into your variable. - Over anything else, Java calls
iterator()once, then asks the iteratorhasNext()before every pass and, while the answer is true, callsnext()and stores the result in your variable. That is the same loop as theIteratorexample above.
That explains the rules on this page. Your variable gets a copy, so assigning to it changes nothing else. The iterator's next() is where a changed list is noticed. And the loop accepts exactly two things: arrays, and objects whose class implements the Iterable interface. A Map does not, which is why you loop over its entrySet().
Make your own class work in a for-each loop#
Implement Iterable<T> and your own objects work in a for-each loop. The one method you write is iterator(), which returns an Iterator<T>: an object with hasNext() and next(). This Countdown counts down from a number. Step through it and watch the loop call hasNext() and next() on every pass:
import java.util.Iterator;import java.util.NoSuchElementException; public class Main { public static void main(String[] args) { for (int n : new Countdown(3)) { System.out.println(n); } System.out.println("Liftoff!"); }} class Countdown implements Iterable<Integer> { private final int start; Countdown(int start) { this.start = start; } public Iterator<Integer> iterator() { return new CountdownIterator(start); }} class CountdownIterator implements Iterator<Integer> { private int current; CountdownIterator(int start) { current = start; } public boolean hasNext() { return current > 0; } public Integer next() { if (!hasNext()) { throw new NoSuchElementException(); } int value = current; current--; return value; }}It prints 3, 2 and 1 on separate lines, then Liftoff!. The loop called iterator() once, next() three times and hasNext() four times: the fourth answer, false, ended it. next() throws NoSuchElementException when nothing is left, as the Iterator documentation asks, in case other code calls it without checking first. The Collections Framework lesson covers iterators in depth.
Is the for-each loop slower than a for loop?#
Not over an array: the specification defines it as the same counting loop you would write yourself. Over a list it uses the list's iterator, and a real difference shows up with a LinkedList. Its documentation says that reaching a position means walking from the nearer end of the list, so a counting loop that calls get(i) walks further and further as the list grows, while the for-each loop steps from each item straight to the next. On an ArrayList, get(i) takes the same short time at any position, so either loop is fine.
The for-each loop vs the forEach() method#
Since Java 8, collections also have a forEach()method. You pass it a lambda, and it runs the lambda once for each item, in the same order a for-each loop would. A map's forEach() hands the lambda both the key and the value:
import java.util.List;import java.util.Map;import java.util.TreeMap; public class Main { public static void main(String[] args) { List<String> names = List.of("Ada", "Grace", "Linus"); names.forEach(name -> System.out.println("Hi, " + name)); names.forEach(System.out::println); Map<String, Integer> ages = new TreeMap<>(); ages.put("Ada", 36); ages.put("Grace", 85); ages.forEach((name, age) -> System.out.println(name + " is " + age)); }}The first call prints Hi, Ada, Hi, Grace and Hi, Linus. The second prints the three names: System.out::println is a method reference, a shorter way to write name -> System.out.println(name). The map prints Ada is 36 and Grace is 85.
for (String name : names) { ... }names.forEach(name -> ...)Iterable.forEach() method.break leaves the loop early, and continue skips to the next item.break or continue. A return inside the lambda ends only the current item.prices.forEach(p -> total += p); fails with local variables referenced from a lambda expression must be final or effectively final. A lambda may read a local variable from outside it, but never change it. Use a for-each loop for totals and counts.Use the for-each loop by default. forEach() fits when the whole body is one short action, such as printing each item.
Questions people ask#
- What are the three types of loops in Java?
- Java has three loop statements:
for,whileanddo-while. Theforstatement comes in two forms, the countingforloop and the for-each loop (also called the enhanced for loop), which is why you sometimes see four loops listed. - How do I get the index in a for-each loop?
- A for-each loop has no index to give you, so keep your own counter and add 1 to it at the end of each pass, or use a counting loop such as
for (int i = 0; i < names.length; i++). Do not callindexOfinside the loop: it returns the position of the first equal item, which is wrong when the list holds duplicates. - Can I remove items from a list inside a for-each loop?
- No. Calling
removeon a list inside a for-each loop over that list usually stops the program with aConcurrentModificationException. Uselist.removeIf(...)with a condition, or loop with anIteratorand call itsremove()method. - Can a for-each loop change the values in an array?
- No: the loop variable holds a copy of the current item, so assigning to it, as in
item = 0;, leaves the array unchanged. To replace values, use a counting loop and write through the index, as inprices[i] = 0;. If the items are objects, changing a field through the loop variable does change the object. - How do I use a for-each loop on a Map?
- Loop over
map.entrySet()and read each entry withgetKey()andgetValue(), for examplefor (Map.Entry<String, Integer> entry : stock.entrySet()). Loop overmap.keySet()for just the keys ormap.values()for just the values. - What is the difference between the for-each loop and forEach() in Java?
- The for-each loop is a statement built into the language that works on arrays and on anything
Iterable, whileforEach()is a method of collections and maps that runs a lambda for each item, as innames.forEach(System.out::println). Inside a for-each loop you can usebreakand update local variables such as a running total; inside aforEach()lambda you can do neither.