Loops

Java · Lesson 11 of 32 6 min read Updated

Computers are good at doing the same thing many times without getting bored. Printing a multiplication table, adding up a month of expenses, checking every seat in a train: all of these need a loop, a block of code that repeats.

Java has four kinds of loops: while, do-while, for and the enhanced for (often called for-each). In this lesson you will learn when to use each one, how to stop or skip with break and continue, and how to avoid the two most common loop bugs.

The while loop

A while loop checks its condition before each round. If the condition is true, the body runs, and then the condition is checked again. When it becomes false, the loop ends. Use while when you do not know in advance how many rounds you need.

Java
public class Savings {
    public static void main(String[] args) {
        int target = 15000;       // a new phone
        int saved = 0;
        int month = 0;

        while (saved < target) {
            month++;
            saved += 2500;
            System.out.println("Month " + month + ": saved Rs " + saved);
        }
        System.out.println("Aarav can buy the phone after " + month + " months.");
    }
}
Output
Month 1: saved Rs 2500
Month 2: saved Rs 5000
Month 3: saved Rs 7500
Month 4: saved Rs 10000
Month 5: saved Rs 12500
Month 6: saved Rs 15000
Aarav can buy the phone after 6 months.

Something inside the loop must change the condition, here saved += 2500. If nothing does, the condition stays true forever and the program never ends. This is an infinite loop; stop it with Ctrl+C in the terminal.

The do-while loop

A do-while loop checks its condition after each round, so the body always runs at least once. It suits tasks like "show the menu, then ask whether to repeat", or counting digits, where even the number 0 has one digit.

Java
public class Digits {
    public static void main(String[] args) {
        int[] numbers = {124001, 7, 0};
        for (int original : numbers) {
            int n = original;
            int count = 0;
            do {
                count++;
                n /= 10;
            } while (n != 0);
            System.out.println(original + " has " + count + " digit(s)");
        }
    }
}
Output
124001 has 6 digit(s)
7 has 1 digit(s)
0 has 1 digit(s)

Each round removes the last digit with integer division by 10. With a plain while (n != 0) loop, the number 0 would wrongly have zero digits. Note the semicolon after while (n != 0): a do-while needs it.

The for loop

When you know how many times to repeat, a for loop keeps everything about the counter in one line. It has three parts separated by semicolons: initialisation (runs once at the start), condition (checked before each round) and update (runs after each round).

Java
public class Table {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            System.out.println("12 x " + i + " = " + (12 * i));
        }

        int sum = 0;
        for (int n = 1; n <= 100; n++) {
            sum += n;
        }
        System.out.println("Sum of 1 to 100: " + sum);

        for (int countdown = 10; countdown > 0; countdown -= 3) {
            System.out.print(countdown + " ");
        }
        System.out.println("Lift off!");
    }
}
Output
12 x 1 = 12
12 x 2 = 24
12 x 3 = 36
12 x 4 = 48
12 x 5 = 60
Sum of 1 to 100: 5050
10 7 4 1 Lift off!

The counter does not have to go up by one: the last loop counts down in steps of 3. A variable declared in the for line, such as i, exists only inside the loop.

The for-each loop

To visit every item in an array or a list, the enhanced for loop is the simplest choice. Read for (String stop : stops) as "for each stop in stops". There is no counter to get wrong.

Java
public class ForEach {
    public static void main(String[] args) {
        String[] stops = {"Model Town", "Bus Stand", "Civil Lines", "College Gate"};
        int[] minutes = {0, 7, 15, 22};

        for (String stop : stops) {
            System.out.println("Next stop: " + stop);
        }

        for (int i = 0; i < stops.length; i++) {
            System.out.println(stops[i] + " is " + minutes[i] + " min from the depot");
        }
    }
}
Output
Next stop: Model Town
Next stop: Bus Stand
Next stop: Civil Lines
Next stop: College Gate
Model Town is 0 min from the depot
Bus Stand is 7 min from the depot
Civil Lines is 15 min from the depot
College Gate is 22 min from the depot

Use for-each when you only need each item. Use a classic for with an index when you need the position, for example to read two arrays side by side as above. Arrays get their own lesson next: Arrays.

break and continue

break leaves a loop immediately. continue skips the rest of the current round and jumps to the next one.

Java
public class Seats {
    public static void main(String[] args) {
        String[] trains = {"Shatabdi", "Intercity", "Jan Shatabdi", "Superfast"};
        int[] freeSeats = {0, 12, 0, 40};

        for (int i = 0; i < trains.length; i++) {
            if (freeSeats[i] == 0) {
                System.out.println(trains[i] + ": sold out, skipping");
                continue;            // jump to the next train
            }
            System.out.println("Booked on " + trains[i]);
            break;                   // stop looking
        }
    }
}
Output
Shatabdi: sold out, skipping
Booked on Intercity

Nested loops and labels

A loop inside another loop is a nested loop. The inner loop runs completely for every single round of the outer loop, which is perfect for rows and columns. A plain break only leaves the innermost loop. To leave both, put a label (a name followed by a colon) before the outer loop and write break label;.

Java
public class Pattern {
    public static void main(String[] args) {
        for (int row = 1; row <= 4; row++) {
            for (int col = 1; col <= row; col++) {
                System.out.print(col + " ");
            }
            System.out.println();
        }

        search:
        for (int row = 1; row <= 3; row++) {
            for (int seat = 1; seat <= 4; seat++) {
                if (row * seat == 6) {
                    System.out.println("Found at row " + row + ", seat " + seat);
                    break search;    // leave BOTH loops
                }
            }
        }
    }
}
Output
1 
1 2 
1 2 3 
1 2 3 4 
Found at row 2, seat 3

Labels are rare in everyday code. If you need one, consider moving the nested loops into a method and using return instead; you will learn how in Methods & Overloading.

Common mistakes

  • Off-by-one errors. An array of length 4 has indexes 0 to 3, so the condition is i < array.length, not i <= array.length. The second version throws ArrayIndexOutOfBoundsException.
  • Infinite loops. Forgetting i++ or saved += ... keeps the condition true forever.
  • A semicolon after for (...) or while (...). for (int i = 0; i < 5; i++); loops five times doing nothing, and the block below runs once.
  • Changing the counter inside a for loop. It makes the number of rounds hard to predict. Let the update part do its job.
  • Using == with decimals as a loop condition. for (double x = 0; x != 1.0; x += 0.1) never ends, because 0.1 is not exact. Use < instead.

Key points

  • while checks the condition first; do-while runs the body at least once.
  • for (init; condition; update) is best when you know how many rounds you need.
  • for (Type item : collection) visits every item without an index.
  • break leaves a loop; continue skips to the next round; break label; leaves nested loops.
  • Indexes run from 0 to length - 1, so loop with i < length.

Exercise

Write Prime.java that prints every prime number from 2 to 30 on one line, and then how many there were. A number is prime if no number from 2 up to its square root divides it exactly. Use a nested loop, and break out of the inner loop as soon as you find a divisor.

Show solution
Java
public class Prime {
    public static void main(String[] args) {
        int count = 0;
        for (int n = 2; n <= 30; n++) {
            boolean prime = true;
            for (int d = 2; d * d <= n; d++) {
                if (n % d == 0) {
                    prime = false;
                    break;
                }
            }
            if (prime) {
                System.out.print(n + " ");
                count++;
            }
        }
        System.out.println();
        System.out.println(count + " primes up to 30");
    }
}
Output
2 3 5 7 11 13 17 19 23 29 
10 primes up to 30

The condition d * d <= n checks divisors only up to the square root, which avoids calling Math.sqrt. The break stops checking as soon as one divisor is found, because one is enough to prove the number is not prime.

Quick Quiz

1. Which loop always runs its body at least once?

2. What does continue do inside a loop?

3. An array has 5 elements. Which loop condition is correct?

4. How do you leave two nested loops at once?

Learn Java with a mentor

Free lessons get you started. Our Java, C & C++ Programming training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call