Loops in Java — for, for-each, while and do-while with Laura’s instalments (and the extra round that always sneaks in)

The first time I wrote a loop in Java to print the four instalments of a tuition fee, I got five. Instalment 0, instalment 1, instalment 2, instalment 3 and instalment 4. I had copied Python’s range(4) as for (int i = 0; i <= 4; i++), with a <= where a < belonged. In Python range took care of the limits; in Java you write them yourself, and a single character gives you an extra round.

Loops are the topic where Java moves furthest from Python in shape and closest to C: if you’ve done the C loops in IC2, the three-part for will look familiar as soon as you see it. In this article we look at Java’s four loops (for, for-each, while and do-while), when to use each one, how to walk through a String character by character, break and continue (also in nested loops) and the usual traps: < versus <=, the ; after the for and the for-each variable that changes nothing.

We come from Java flow control, so we already have Scanner and if. The output is real, from Java 21 on my computer, which is set to Spanish: that’s why decimals typed and printed with printf use a comma (45,00 €). On a computer set to English you’d see a point. Where the program asks for data, you’ll see what was typed after each prompt.

The for loop with an index: the three-part structure

In Python, a for always goes through something (a list, a range, a text). Java’s classic for is a counter with three parts separated by semicolons:

for (initialisation; condition; update) {
    body
}
The order of the four parts of a forThe for runs int i = 0 once; then it repeats: checks i < 3, runs the body if it is true and does i++. With i equal to 3 the condition is false and the loop ends after three rounds.for (int i = 0; i < 3; i++) { … }1int i = 0once only2i < 3 ?before every round3bodyif it was true4i++false: leaves with i = 3i = 0 → 0 < 3 true → bodyi = 1 → 1 < 3 true → bodyi = 2 → 2 < 3 true → bodyi = 3 → 3 < 3 false → end
The condition is checked before every round, including the last one: that is why i ends up as 3, not 2.
  1. Initialisation (int i = 0): runs once only, at the start.
  2. Condition (i < 3): checked before every round. If it’s true, the body runs; if it’s false, the loop ends.
  3. Body: what gets repeated.
  4. Update (i++): runs after every round, and we go back to step 2.

Look at the last row of the trace in the picture: the condition is also checked when i is 3, gives false and the loop ends. The body has run three times (0, 1 and 2), but i has reached 3.

The for loop with a range: Python equivalents

How do you write for i in range(...) in Java? Like this, the four forms of range in one program:

/** The three-part for: start; condition; step. */
public class BasicFor {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            System.out.println("Round with i = " + i);
        }
        System.out.println("--- range(2, 7) ---");
        for (int i = 2; i < 7; i++) {
            System.out.print(i + " ");
        }
        System.out.println();
        System.out.println("--- range(0, 10, 2) ---");
        for (int i = 0; i < 10; i += 2) {
            System.out.print(i + " ");
        }
        System.out.println();
        System.out.println("--- range(5, 0, -1) ---");
        for (int i = 5; i > 0; i--) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}
Round with i = 0
Round with i = 1
Round with i = 2
Round with i = 3
Round with i = 4
--- range(2, 7) ---
2 3 4 5 6 
--- range(0, 10, 2) ---
0 2 4 6 8 
--- range(5, 0, -1) ---
5 4 3 2 1 
PythonJavaValues
for i in range(5)for (int i = 0; i < 5; i++)0 1 2 3 4
for i in range(2, 7)for (int i = 2; i < 7; i++)2 3 4 5 6
for i in range(0, 10, 2)for (int i = 0; i < 10; i += 2)0 2 4 6 8
for i in range(5, 0, -1)for (int i = 5; i > 0; i--)5 4 3 2 1

The translation trick: the end of range is never included, so in Java it goes with < (or > going backwards), not <=. More work than in Python, but also more freedom: you can step 3 at a time, multiply (i *= 2) or use any condition.

< versus <=: the extra round

My five-instalment loop, next to the two good loops:

/** < versus <=: the extra (or missing) round. Laura pays 4 instalments. */
public class OneTooMany {
    public static void main(String[] args) {
        final int INSTALMENTS = 4;
        System.out.print("With <  starting at 0: ");
        for (int i = 0; i < INSTALMENTS; i++) {
            System.out.print("instalment " + i + "  ");
        }
        System.out.println();
        System.out.print("With <= starting at 1: ");
        for (int i = 1; i <= INSTALMENTS; i++) {
            System.out.print("instalment " + i + "  ");
        }
        System.out.println();
        System.out.print("With <= starting at 0: ");
        for (int i = 0; i <= INSTALMENTS; i++) {
            System.out.print("instalment " + i + "  ");
        }
        System.out.println();
        int j;
        for (j = 0; j < INSTALMENTS; j++) {
            // the body does nothing: we only want to see j on the way out
        }
        System.out.println("On leaving the for, j is " + j);
    }
}
With <  starting at 0: instalment 0  instalment 1  instalment 2  instalment 3  
With <= starting at 1: instalment 1  instalment 2  instalment 3  instalment 4  
With <= starting at 0: instalment 0  instalment 1  instalment 2  instalment 3  instalment 4  
On leaving the for, j is 4
  • Starting at 0 you use <: i < 4 gives rounds 0, 1, 2 and 3. Four.
  • Starting at 1 you use <=: i <= 4 gives 1, 2, 3 and 4. Four.
  • Starting at 0 with <= you get five. It’s the off-by-one error, and with arrays (coming topics) that extra instalment turns into an ArrayIndexOutOfBoundsException.
  • The last line proves what the picture said: on leaving the for, j is 4, not 3.

Mixing = 0 with <=. A rule that never fails: if you start at 0, < and the number of rounds; if you start at 1, <= and the number of rounds.

i++, i–, i += n: the increment operators

Java has ++ and --, which Python doesn’t (there’s no i++ in Python, you write i += 1). There are also the compound +=, -=, *=, /= and %=. And there are two forms of ++:

/** i++ versus ++i: inside an expression they are not the same. */
public class IncrementTrap {
    public static void main(String[] args) {
        int a = 5;
        int b = a++;          // first uses 5 and then goes up to 6
        int c = 5;
        int d = ++c;          // first goes up to 6 and then uses it
        System.out.println("a = " + a + ", b = " + b);
        System.out.println("c = " + c + ", d = " + d);
        for (int i = 0; i < 3; ++i) {      // in the step of a for it makes no difference
            System.out.print(i + " ");
        }
        System.out.println();
    }
}
a = 6, b = 5
c = 6, d = 6
0 1 2 

b = a++ uses the old value (5) and then raises a; d = ++c raises first and uses the new value (6). In the step of a for it doesn’t matter which you write, because the value isn’t used for anything else: that’s why both versions give 0, 1, 2. Use i++ out of habit and avoid ++ inside longer expressions.

Declaring the loop variable in Java

If you declare the variable inside the for (int i = 0), it only exists inside the loop:

public class OutsideTheFor {
    public static void main(String[] args) {
        for (int i = 0; i < 4; i++) {
            System.out.println("instalment " + i);
        }
        System.out.println("Last: " + i);
    }
}
OutsideTheFor.java:6: error: cannot find symbol
        System.out.println("Last: " + i);
                                      ^
  symbol:   variable i
  location: class OutsideTheFor
1 error

cannot find symbol: outside the for, i doesn’t exist. In Python the for variable was still alive after the loop; in Java it isn’t. If you need it afterwards (to know where it stopped), declare it before the loop, like j in the instalments program. For the same reason, in two loops one after the other you can use int i again without any problem: each i belongs to its loop.

The for-each loop: when you don’t need the index

The for-each (or «enhanced for») goes through the elements of a collection one by one, with no index: it’s the closest thing to Python’s for grade in grades:. We need something to go through, so we bring arrays forward a little (several values of the same type under one name, with their own topic later on): for now it’s enough to know that {7.5, 8.0, 6.5} creates one, that grades[i] is the element at position i and that grades.length says how many there are.

/** for-each: goes through each element with no index. The grades are in an array (arrays have their own topic). */
public class ForEach {
    public static void main(String[] args) {
        double[] grades = {7.5, 8.0, 6.5, 9.0, 5.5};     // an array: several doubles under one name
        double sum = 0;
        for (double grade : grades) {                    // «for each grade in grades»
            sum += grade;
        }
        System.out.printf("Average: %.2f%n", sum / grades.length);

        for (int i = 0; i < grades.length; i++) {        // with an index: we know the position
            System.out.println("Grade " + (i + 1) + ": " + grades[i]);
        }

        String subject = "FP2";
        for (char c : subject.toCharArray()) {           // a String is walked through with toCharArray()
            System.out.print("[" + c + "]");
        }
        System.out.println();
    }
}
Average: 7,30
Nota 1: 7.5
Nota 2: 8.0
Nota 3: 6.5
Nota 4: 9.0
Nota 5: 5.5
[F][P][2]
  • for (double grade : grades) reads «for each grade in grades». The variable’s type has to be the elements’ type.
  • The average: (7.5 + 8 + 6.5 + 9 + 5.5) / 5 = 36.5 / 5 = 7.30.
  • With the index for we know the position (i + 1 to number from 1, the way a person would say it).
  • A String can’t be walked through directly with for-each, but toCharArray() turns it into an array of char.

Is there a Java for-each in Python?

Yes: it’s Python’s normal for. for grade in grades: is exactly Java’s for-each. What doesn’t exist in Python is the three-part for; its equivalent is for i in range(...). And the other way round: Python’s for i in is written in Java as a for-each if you go through elements or as for (int i = …; …; i++) if you go through numbers.

When to use for-each and when a for with index

There’s a difference you can’t see at first sight: the for-each variable is a copy of each element. Changing it doesn’t change the array:

/** The for-each variable is a copy: changing it doesn't change the array. */
public class ForEachNoChange {
    public static void main(String[] args) {
        double[] grades = {7.5, 4.0, 6.5};
        for (double grade : grades) {
            grade = grade + 1;            // raises the copy, not the array
        }
        System.out.println("After the for-each: " + grades[0] + " " + grades[1] + " " + grades[2]);
        for (int i = 0; i < grades.length; i++) {
            grades[i] = grades[i] + 1;    // with an index the array does change
        }
        System.out.println("After the for with index: " + grades[0] + " " + grades[1] + " " + grades[2]);
    }
}
After the for-each: 7.5 4.0 6.5
After the for with index: 8.5 5.0 7.5
I need…I use
Just to read each element (add, search, print)for-each
The element’s positionfor with index
To change the elementsfor with index
To go backwards or skipfor with index
To repeat something N times, with no collectionfor with index

The while loop: when you don’t know how many rounds there’ll be

The while is like Python’s with brackets and braces: it checks the condition before every round. It’s the natural loop when you don’t know how many rounds there’ll be: Laura saves 45 € a week to pay her 306,30 € tuition (in cents, as in the variables practice). How many weeks does she need?

/** while: we do not know how many rounds there will be. Laura saves 45 € a week for her 306,30 € tuition. */
public class Savings {
    public static void main(String[] args) {
        final int TUITION = 30630;         // in cents
        final int WEEKLY_SAVING = 4500;
        int saved = 0;
        int weeks = 0;
        while (saved < TUITION) {          // checked BEFORE every round
            saved += WEEKLY_SAVING;
            weeks++;
            System.out.printf("Week %d: %.2f €%n", weeks, saved / 100.0);
        }
        System.out.printf("In %d weeks; %.2f € left over%n", weeks, (saved - TUITION) / 100.0);
    }
}
Week 1: 45,00 €
Week 2: 90,00 €
Week 3: 135,00 €
Week 4: 180,00 €
Week 5: 225,00 €
Week 6: 270,00 €
Week 7: 315,00 €
In 7 weeks; 8,70 €

Check: 6 weeks are 270 € (not enough) and 7 are 315 €; 315 − 306.30 = 8.70 € left over. Nobody knew in advance it would be 7 rounds: that’s what a while does. If the condition were false from the start (for example, with the tuition already paid), the body wouldn’t run even once.

Reading up to a sentinel: while (true) and break

Another typical use: reading data until a special value arrives (the sentinel). With while (true) the loop doesn’t end by itself; a break stops it when the -1 shows up:

import java.util.Scanner;

/** Reading grades up to a sentinel value (-1) with while (true) and break. */
public class Sentinel {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        double sum = 0;
        int count = 0;
        System.out.println("Type the grades (-1 to finish):");
        while (true) {
            System.out.print("Grade: ");
            double grade = sc.nextDouble();
            if (grade == -1) {
                break;                         // leaves the while
            }
            sum += grade;
            count++;
        }
        if (count > 0) {
            System.out.printf("%d grades, average %.2f%n", count, sum / count);
        }
        sc.close();
    }
}
Type the grades (-1 to finish):
Grade: 7,5
Grade: 8
Grade: 6,5
Grade: -1
3 grades, average 7,33

Average: (7.5 + 8 + 6.5) / 3 = 22 / 3 = 7.33. The -1 doesn’t count: the break leaves before adding it. Why if (count > 0) before dividing? Because if the first number were -1, count would be 0 and the average would be 0/0, which in double gives NaN (Not a Number).

A while whose condition never changes inside the body. If you forget saved += WEEKLY_SAVING, the loop never ends and the program hangs (in the terminal you stop it with Ctrl+C).

The do-while loop: run at least once

do-while doesn’t exist in Python. It’s a while with the question at the end: first it runs the body and then it decides whether to repeat. That way it runs at least once.

while asks first; do-while, afterwardsIn a while the condition is checked before the body, so it may never run. In a do-while the body comes first and the condition afterwards: it runs at least once.whiledo-whilecondition?bodytruefalsemay run 0 timesbodycondition?truefalseat least 1 rounddo { … } while (option != 3); ← a do-while ends with a semicolon
For a menu or to validate what the user types, do-while fits: first you ask and then you check.

It fits menus: the menu is always shown a first time and repeats until you choose to leave.

import java.util.Scanner;

/** do-while: the menu is shown at least once and repeats until you choose Exit. */
public class MenuDoWhile {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int option;
        do {
            System.out.println("1) Timetable  2) Grades  3) Exit");
            System.out.print("Option: ");
            option = sc.nextInt();
            switch (option) {
                case 1 -> System.out.println("Monday and Wednesday: FP2 at 9:00");
                case 2 -> System.out.println("FP2: 7,1 · IC2: 6,4");
                case 3 -> System.out.println("See you, Laura");
                default -> System.out.println("Not a valid option: " + option);
            }
        } while (option != 3);                 // mind the ; at the end
        sc.close();
    }
}
1) Timetable  2) Grades  3) Exit
Option: 5
Not a valid option: 5
1) Timetable  2) Grades  3) Exit
Option: 2
FP2: 7,1 · IC2: 6,4
1) Timetable  2) Grades  3) Exit
Option: 3
See you, Laura

5 (not valid), 2 and 3 were typed. With a normal while you’d have to give option a made-up value before the loop to get in; with do-while, there’s no need. The switch with arrows is the one from the previous topic.

And to validate what the user types, the same pattern: ask and repeat while the data is bad.

import java.util.Scanner;

/** do-while to validate: the grade is asked for until it is between 0 and 10. */
public class ValidateGrade {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        double grade;
        do {
            System.out.print("Grade (0-10): ");
            grade = sc.nextDouble();
        } while (grade < 0 || grade > 10);
        System.out.println("Grade saved: " + grade);
        sc.close();
    }
}
Grade (0-10): 12
Grade (0-10): -3
Grade (0-10): 8,5
Grade saved: 8.5

do-while is the only loop that ends in a semicolon: } while (option != 3);. In the other loops, a ; after the bracket is a mistake (we see it below).

break and continue

break leaves the loop right there; continue skips the rest of this round and moves on to the next. They work as in Python and C:

/** break leaves the loop; continue jumps to the next round. */
public class BreakContinue {
    public static void main(String[] args) {
        double[] grades = {7.5, 8.0, 4.5, 9.0, 3.0};
        for (int i = 0; i < grades.length; i++) {
            if (grades[i] < 5) {
                System.out.println("First fail: position " + i + " (" + grades[i] + ")");
                break;                             // we have it: no need to carry on
            }
        }
        System.out.print("Passes only: ");
        for (double grade : grades) {
            if (grade < 5) {
                continue;                          // skips this round
            }
            System.out.print(grade + " ");
        }
        System.out.println();
    }
}
First fail: position 2 (4.5)
Passes only: 7.5 8.0 9.0 
  • The first for looks for the first fail: at position 2 there’s a 4.5, and the break avoids looking at the rest (no need: we have it).
  • The second one skips the fails with continue and prints only the passes: 7.5, 8 and 9 (4.5 and 3 are skipped).

The ; after the for

The same trap as the ; after the if in the previous topic:

/** A ; after the for is an empty loop: the block below runs only once. */
public class ForSemicolon {
    public static void main(String[] args) {
        int i;
        for (i = 0; i < 3; i++); {
            System.out.println("Round " + i);
        }
    }
}
Round 3

A single line, «Round 3». The ; is the (empty) body of the for: the loop does its three rounds doing nothing and leaves i at 3. Then the block in braces runs once. javac gives no warning.

How to walk through a String character by character

In Python, for c in text: and that’s it. In Java a String can’t be walked through directly with for-each, so there are two ways. The example uses the Spanish name of the FP2 subject, Fundamentos de Programación II (Programming Fundamentals II), so that the counts match the output.

Way 1: with charAt() and the index

charAt(i) gives the character at position i, and length() (with brackets: it’s a method) says how many there are. Positions go from 0 to length() - 1, so the condition is i < text.length().

Way 2: with toCharArray() and for-each

toCharArray() turns the text into an array of char, which does accept for-each. Both ways in one program, plus walking backwards:

/** Walking through a String: charAt(i) with an index or toCharArray() with for-each. */
public class WalkText {
    public static void main(String[] args) {
        String subject = "Fundamentos de Programación II";
        int vowels = 0;
        int spaces = 0;
        for (int i = 0; i < subject.length(); i++) {      // length() with brackets: it is a method
            char c = Character.toLowerCase(subject.charAt(i));
            if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
                vowels++;
            } else if (c == ' ') {
                spaces++;
            }
        }
        System.out.println(subject + " (" + subject.length() + " characters)");
        System.out.println("Vowels without accent: " + vowels + ", spaces: " + spaces);

        String capitals = "";
        for (char c : subject.toCharArray()) {
            if (Character.isUpperCase(c)) {
                capitals += c;                                  // F, P, I, I
            }
        }
        System.out.println("Capitals: " + capitals);

        String reversed = "";
        for (int i = subject.length() - 1; i >= 0; i--) { // backwards: from the last one to 0
            reversed += subject.charAt(i);
        }
        System.out.println("Backwards: " + reversed);
    }
}
Fundamentos de Programación II (30 characters)
Vowels without accent: 11, spaces: 3
Capitals: FPII
Backwards: II nóicamargorP ed sotnemadnuF
  • It counts 11 vowels «without an accent»: the ó in «Programación» isn’t 'o' (it’s another character), so it doesn’t get in. In a real program you’d have to add it to the condition.
  • capitals += c keeps sticking the capital letters on: F, P, I, I.
  • Backwards: the index starts at length() - 1 (the last one, 29) and goes down to 0 with i >= 0. Starting at length() would give a StringIndexOutOfBoundsException.

length() with brackets for Strings and length without brackets for arrays (grades.length). It’s one of the most typical compile errors in FP2.

Nested loops: how not to get lost

A loop inside another: the inner one does all its rounds for every round of the outer one. A multiplication table with 4 rows and 5 columns:

/** Nested loops: the inner one does all its rounds for every round of the outer one. */
public class Table {
    public static void main(String[] args) {
        for (int row = 1; row <= 4; row++) {
            for (int col = 1; col <= 5; col++) {
                System.out.printf("%4d", row * col);
            }
            System.out.println();                  // at the end of each row
        }
    }
}
   1   2   3   4   5
   2   4   6   8  10
   3   6   9  12  15
   4   8  12  16  20

For row = 1, col goes from 1 to 5; then row = 2 and col starts again at 1. In total, 4 × 5 = 20 rounds of the inner loop. %4d gives each number 4 characters, and the println() at the end of each row starts a new line. Use names that say what each loop goes through (row, col) or, at least, i, j, k: two variables with the same name in nested loops don’t compile.

break in nested loops: it only leaves the inner one

Finding the free seat in a room with 3 rows and 4 seats (the free one, made up, is row 1, seat 2), counting how many seats are checked:

/** break in nested loops: it only leaves the inner loop. With a flag (or a label) we leave both. */
public class FindSeat {
    public static void main(String[] args) {
        // Room with 3 rows and 4 seats: the free seat is in row 1, seat 2 (made up)
        final int FREE_ROW = 1, FREE_SEAT = 2;
        int rounds = 0;
        for (int f = 0; f < 3; f++) {
            for (int a = 0; a < 4; a++) {
                rounds++;
                if (f == FREE_ROW && a == FREE_SEAT) {
                    System.out.println("Free: row " + f + ", seat " + a);
                    break;                         // only leaves the seats for
                }
            }
        }
        System.out.println("Without a flag: " + rounds + " rounds");

        rounds = 0;
        boolean found = false;
        for (int f = 0; f < 3 && !found; f++) {     // the flag stops the outer one too
            for (int a = 0; a < 4; a++) {
                rounds++;
                if (f == FREE_ROW && a == FREE_SEAT) {
                    found = true;
                    break;
                }
            }
        }
        System.out.println("With a flag: " + rounds + " rounds");

        rounds = 0;
        room:                                              // label of the outer loop
        for (int f = 0; f < 3; f++) {
            for (int a = 0; a < 4; a++) {
                rounds++;
                if (f == FREE_ROW && a == FREE_SEAT) {
                    break room;                            // leaves both
                }
            }
        }
        System.out.println("With break room: " + rounds + " rounds");
    }
}
Free: row 1, seat 2
Without a flag: 11 rounds
With a flag: 7 rounds
With break room: 7 rounds
Finding the free seat: break in nested loopsA room with 3 rows and 4 seats, the free seat in row 1, seat 2. With only break 11 seats are visited because row 2 is still walked through; with a flag or with break aula, 7.Only break: 11 roundsrow 01234row 1567row 2891011break only leaves the seats loop:row 2 is still walked throughWith a flag or break room: 7 roundsrow 01234row 1567row 2the flag (or the label) stopsthe rows loop as well
The numbers are the order of the rounds. The green seat is the free one.

With only break, 11 seats are checked: the break leaves the seats loop, but the rows loop carries on and goes through the whole of row 2. With a flag (found, which also cuts the outer loop’s condition) 7 are checked. And Java has a third option Python doesn’t: give the outer loop a label (room:) and leave both with break room;.

A complete program with all the loops

The tuition receipt depending on the subjects Laura chooses: do-while to validate how many there are, for to read each one’s credits, for-each to add them up and while to split the total into instalments of at most 100 € (made-up rules). The credits array is created with new int[n]: n slots for integers, which the for fills in.

import java.util.Scanner;

/** All together: do-while to validate, for to read, for-each to walk through and while for the instalments. */
public class SubjectReceipt {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        final double CREDIT_PRICE = 15.50;
        int n;
        do {
            System.out.print("How many subjects (1-6)? ");
            n = sc.nextInt();
        } while (n < 1 || n > 6);

        int[] credits = new int[n];                      // one slot per subject
        for (int i = 0; i < n; i++) {
            System.out.print("Credits for subject " + (i + 1) + ": ");
            credits[i] = sc.nextInt();
        }
        int total = 0;
        for (int c : credits) {
            total += c;
        }
        int cents = (int) Math.round(total * CREDIT_PRICE * 100);
        System.out.printf("%d credits → %.2f €%n", total, cents / 100.0);

        int instalment = 1;
        while (cents > 0) {                              // instalments of at most 100 €
            int payment = Math.min(cents, 10000);
            System.out.printf("Instalment %d: %.2f €%n", instalment, payment / 100.0);
            cents -= payment;
            instalment++;
        }
        sc.close();
    }
}
How many subjects (1-6)? 9
How many subjects (1-6)? 4
Credits for subject 1: 6
Credits for subject 2: 6
Credits for subject 3: 6
Credits for subject 4: 6
24 credits → 372,00 €
Instalment 1: 100,00 €
Instalment 2: 100,00 €
Instalment 3: 100,00 €
Instalment 4: 72,00 €

First a 9 was typed (outside 1-6) and the do-while asked again. Then 4 subjects of 6 credits: 24 credits × 15.50 € = 372.00 €. The while splits it: 100 + 100 + 100 + 72 = 372. Math.min(cents, 10000) takes 100 € or whatever is left if it’s less, and the loop ends when cents reaches 0.

Common mistakes with loops

  • One round too many or too few: = 0 with <=. From 0, <; from 1, <=.
  • Using the for variable outside: it doesn’t exist; declare it before if you need it.
  • Changing the for-each variable: it’s a copy; to change elements, a for with index.
  • A while that never ends: something in the body has to bring the condition closer to false.
  • ; after the for or the while: empty body. Only do-while ends in ;.
  • break in nested loops: it only leaves the inner loop; a flag or a label to leave both.
  • length() versus length: a method in Strings, an attribute in arrays.

Watch it step by step in Python Tutor

pythontutor.com shows how the variables change in every round, which is exactly what’s hard to see in a loop. Choose Java and paste:

public class LoopTutor {
    public static void main(String[] args) {
        int sum = 0;
        for (int i = 1; i <= 4; i++) {
            sum += i;
        }
        int saved = 0;
        int weeks = 0;
        while (saved < 100) {
            saved += 45;
            weeks++;
        }
        String text = "FP2";
        String reversed = "";
        for (int i = text.length() - 1; i >= 0; i--) {
            reversed += text.charAt(i);
        }
        System.out.println(sum + " " + weeks + " " + reversed);
    }
}

Output:

10 3 2PF

What to watch step by step:

  1. In the sum for, see how i and sum change together: 1 → 1, 2 → 3, 3 → 6, 4 → 10. Then i disappears from the panel: it only existed inside the loop.
  2. In the while, saved goes through 45, 90 and 135, and weeks through 1, 2 and 3. On the fourth check (135 < 100 is false) the loop ends.
  3. In the backwards walk, i starts at 2 (the last index of «FP2») and reversed grows letter by letter: «2», «2P», «2PF».
  4. Count how many times the arrow passes the condition of each loop: always one more than the rounds of the body.

Quick summary

I want…Loop
Repeat N times or go through positionsfor (int i = 0; i < n; i++)
Go through the elements with no indexfor (double x : grades)
Repeat while something holds, not knowing how many timeswhile (condition)
Run at least once (menu, validation)do { … } while (condition);
Leave the loopbreak (or break label; in nested loops)
Jump to the next roundcontinue
Walk through a StringcharAt(i) with i < s.length(), or s.toCharArray()

Three ideas to keep:

  1. The condition is checked before every round (including the one that ends the loop): from 0 use <, from 1 <=.
  2. for-each to read, a for with index to change or know the position, while when you don’t know how many rounds and do-while when there’s at least one.
  3. break only leaves one loop: in nested loops, a flag or a label.

Now it’s your turn in the Java loops practice, with complete programs that put loops, Scanner and conditions together. And if you come from Java flow control with doubts about the if or the switch that appear in here, go over it before carrying on.

Next step: practiceJava loops practice — a text analyser, the guessing game that finally repeats and a pattern generator (and the extra round that crashed my program)

Did this article help you? Here is how you can support SergioLearns →