Java for Loops: Explained with Examples

by Diogo Kollross

8 min read

Repetition, together with decision and code reuse, is one of the building blocks of any programming language. Java followed the tradition of C-family programming languages and offered a for loop since version 1. Java 5 introduced a for-each loop, giving us an easier form of iteration over arrays and collections.

Basic for Statement

This is the basic for loop you find in C-family programming languages. It is also known as a numeric loop.

It has three parts, separated by a semicolon: initialization, condition, and advancement. All three parts are optional, though most of the time you'll need them all.

for (<initialization>; <condition>; <advancement>) {
    // 
}

In the first part, initialization, you'll initialize the control variable that is used to check when the loop should finish. As that control variable is usually only used inside the loop, it's common to also declare it in the initialization part of the for loop.

for (int i = 0; <condition>; <advancement>) {
    // 
}

The next part is the condition, where we decide if the loop is over. In Java, you need to write an expression that returns a boolean. When we're using the loop as a counter, which is the most frequent case, we compare the control variable with an upper limit - but that is not a requirement and depends on the algorithm you're coding.

for (int i = 0; i < 5; <advancement>) {
    // 
}

Finally, the advancement part is where you make the control variable proceed to the next value. When counting, you simply increment the control variable.

for (int i = 0; i < 5; i++) {
    System.out.println(i);
}
/*
0
1
2
3
4
*/

The code above will print numbers from 0 to 4, which is perfect to iterate over a 5-items array like in the example below.

int[] myArray = new int[] { 10, 15, 20, 31, 25 };
for (int i = 0; i < 5; i++) {
    int element = myArray[i];
    System.out.println(element);
}
/*
10
15
20
31
25
*/

Most of the time we'll iterate from 0 to n-1 (where n is the size of the collection) because in Java these collections are indexed starting from zero. If you need to count from 1 to n, just remember to replace < with <= in the condition.

for (int i = 1; i <= 5; i++) {
    System.out.println(i);
}
/*
1
2
3
4
5
*/

Enhanced for Statement

Since version 5, Java has an enhanced for statement - also known as for-each loop. This kind of for allows you to iterate over arrays or lists without having to calculate the index of each element or explicitly advancing an Iterable.

The enhanced for has this format:

for (<loop variable> : <iterable>) {
    //
}

The loop variable is a declaration of a variable that will assume the value of each element during the iteration. The iterable part may be an array or an object whose class implements the Iterable interface. Some common examples are Collection, List, ArrayList, and Set.

The above example, that prints all elements of an array, would be coded like this:

int[] myArray = new int[] { 10, 15, 20, 31, 25 };
for (int element : myArray) {
    System.out.println(element);
}
/*
10
15
20
31
25
*/

Notice how we don't need to calculate the index of each element. We also don't need a line just to get the indexed element from the array. As the enhanced for is shorter and more readable, it's preferable in most use cases.

Break and Continue

Break

Sometimes there is a need to break out of the loop. In other words, you stop iterating and jump directly to the first statement after the for body. One really frequent use of the break statement is when searching for an element:

List<String> colorList = Arrays.asList("Cyan", "AliceBlue",
    "Violet", "Gold");
String startingWithA = null;
for (String color : colorList) {
    if (color.charAt(0) == 'A') {
        startingWithA = color;
        break;
    }
}
System.out.println(startingWithA);
/*
AliceBlue
*/

The above code will find the first element that starts with A, or leave the variable startingWithA unchanged with the value null if there was no element starting with that letter.

Some algorithms require nested loops and the need to break the outer loop from inside the inner loop. One option for that situation is to extract that fragment to a function and then use a return statement to exit from the function itself.

private String selectColor(char[] interestingLetters,
        Iterable<String> colorList) {
    for (char interestingLetter : interestingLetters) {
        for (String color : colorList) {
            if (color.charAt(0) == interestingLetter) {
                return color;
            }
        }
    }
    
    return null;
}
 
private void printSelectedColor() {
    char[] interestingLetters = new char[] { 'X', 'V' };
    List<String> colorList = Arrays.asList("Cyan", "AliceBlue",
        "Violet", "Gold");
    String selectedColor = selectColor(interestingLetters, colorList);
    System.out.println(selectedColor);
}
/*
Violet
*/

The code above uses that strategy: we have a selectColor function that finds the first color that starts with any of the interesting letters it received in the first parameter. As we needed to break all the loops at once, we used the return statement there. We couldn't have that return inside the printSelectedColor function because then we would exit that function too early and the following line (the call to println) wouldn't execute.

Continue

The continue statement skips the rest of the for body and starts the next iteration. It's useful to flatten big ifs that enclose the for body entirely.

The following example creates a list with color names that start with a G and have up to 5 characters:

List<String> colorList = Arrays.asList("Green", "AliceBlue",
    "Violet", "GreenYellow");
List<String> shortStartingWithG = new ArrayList<>();
for (String color : colorList) {
    if (color.charAt(0) == 'G') {
        if (color.length() <= 5) {
            shortStartingWithG.add(color);
        }
    }
}
System.out.println(shortStartingWithG);
/*
[Green]
*/

This works but look at all the indentation needed inside the for body. That is considered to be less readable and one way to fix it is to use the continue statement as shown below.

List<String> colorList = Arrays.asList("Green", "AliceBlue",
    "Violet", "GreenYellow");
List<String> shortStartingWithG = new ArrayList<>();
for (String color : colorList) {
    if (color.charAt(0) != 'G') {
        continue;
    }
 
    if (color.length() > 5) {
        continue;
    }
    
    shortStartingWithG.add(color);
}
System.out.println(shortStartingWithG);
/*
[Green]
*/

Advanced Use Cases

For-Each with index

There are times where you want or need to use a for-each loop but also need the index. For these situations, you can calculate the index explicitly. Just remember to initialize the counter right before the loop, and to increment it just before closing the loop body:

List<String> colorList = Arrays.asList("Cyan", "AliceBlue",
    "Violet", "Gold");
int i = 1;
for (String color : colorList) {
    System.out.println(i + " - " + color);
    i++;
}
/*
1 - Cyan
2 - AliceBlue
3 - Violet
4 - Gold
*/

Iterator Interface

The enhanced for statement works out of the box with the modern Iterable interface, but there are a few classes in the JDK that use more ancient interfaces. One of these almost deprecated interfaces is the Iterator interface. It's implemented, for example, by the Scanner class. The Scanner class can be used to parse space-separated words or other primitives (like integers or floats) from a string. We could use the basic for loop to iterate over its result.

String input = "10   15 20   35";
for (Scanner scanner = new Scanner(input); scanner.hasNextInt();) {
    int number = scanner.nextInt();
    System.out.println(number);
}
/*
10
15
20
35
*/

As you can see, the advancement part of the loop is unused because it is not needed in this case. Arguably, Iterators are best iterated using the while statement as it's slightly more readable:

String input = "10   15 20   35";
Scanner scanner = new Scanner(input);
while (scanner.hasNextInt()) {
    int number = scanner.nextInt();
    System.out.println(number);
}
/*
10
15
20
35
*/

Enumeration

Another ancient interface is Enumeration. This interface is used to list the files inside a ZIP file when using the ZipFile class. Again, we can iterate over its entries with a basic for loop:

ZipFile file = new ZipFile("example.zip");
for (Enumeration<? extends ZipEntry> entries = file.entries();
        entries.hasMoreElements();) {
    ZipEntry entry = entries.nextElement();
    System.out.println(entry.getName());
}

Like in the Iterator example, we're not using the third part of the loop and could rewrite it using the while statement:

ZipFile file = new ZipFile("example.zip");
Enumeration<? extends ZipEntry> entries = file.entries();
while (entries.hasMoreElements()) {
    ZipEntry entry = entries.nextElement();
    System.out.println(entry.getName());
}

Conclusion

To summarize, Java offers several options to iterate over many kinds of sequences.

Most of the time, using the for-each command will be the most readable option when working with arrays, lists, and anything similar - even in those cases when you also need an index to pair with each element.

Some exceptions are: using the basic for loop when all you need is a sequence of numbers, and using the while command to iterate over objects that implement the Iterator or Enumeration interfaces.

FAQs

Q: How to handle infinite loops and avoid them in Java?
To avoid infinite loops in Java, ensure the loop's condition will eventually become false. Use a control variable, increment it within the loop, and set a clear exit condition. For while and do-while loops, carefully structure conditions to prevent endless execution. Catching errors and implementing timeout mechanisms can also prevent unintended infinite loops.
Q: Are there performance differences between traditional for loops and enhanced for-each loops?
Traditional for loops may be slightly faster for primitive data types due to direct access and manipulation. Enhanced for-each loops offer better readability and are preferred for collections but may incur slight overhead when iterating over large datasets.
Q: How to use for loops with Java 8 streams or functional programming techniques?
Use Java 8 streams by converting collections into streams, then applying operations like filter, map, and reduce. For example, list.stream().filter(e -> e > 10).forEach(System.out::println) replaces a for loop for filtering and acting on elements.
Diogo Kollross
Diogo Kollross
Senior Full-stack Developer

Diogo Kollross is a Full-stack Engineer with more than 14 years of professional experience using many different tech stacks. He likes programming since he was a child, and enjoys good food and traveling.

Expertise
  • Node.js
  • JavaScript
  • ReactJS
  • Vue.js
  • PHP
  • Laravel
  • +1

Ready to start?

Get in touch or schedule a call.