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

In the FP2 lab we were asked to count the letters in a sentence. Dead easy, I thought: a for that goes from 0 up to the length and that’s it. I wrote it with i <= sentence.length(), because “up to the length” sounded to me like “length included”. The program printed every letter, one by one, perfect… and in the last round it blew up with a StringIndexOutOfBoundsException that took up half the screen. I had one round too many. That extra = is the most typical loop mistake, and in this practice you’ll trigger it on purpose, with its real message, before writing the program properly.

If you come from the Java loops theory, you already know the three-part for, for-each, while, do-while, break and continue. Today we use them in three medium-level programs: a text analyser that walks through one of Laura’s sentences character by character (with an index, backwards and with two indexes at once), the guessing game from the flow control practice rewritten with a while (the promise from that article: the same game without copying the block three times) and a pattern generator with a do-while menu and nested loops. The data comes from the keyboard and brings surprises: accents, capitals, out-of-range numbers and options that don’t exist.

As in the theory, there are no arrays here: they have their own topic later on. toCharArray() only appears to walk through a text with for-each, just like there.

Before you start

Make sure you are clear on:

  • The three parts of a for: start, condition and step, and the order in which they run.
  • That the positions of a String go from 0 to length() - 1, and that charAt(i) returns the character at position i.
  • The difference between while (it may never run) and do-while (it runs at least once).
  • What break (leaves the loop) and continue (skips the rest of that round) do.

If any of these sounds shaky, go back to the theory before carrying on.

Create a loops_practice folder with one .java file per program. The outputs in this article are real, from a single run with Java 21 on a computer set to Spanish: what you see after each question is what was typed, and the sentences typed in are Spanish (the counts depend on their letters, so they are left as they were). In the site’s Java playground the typed data goes in the Input tab, one line per value. And if one of your loops never ends, stop it in the terminal with Ctrl + C.

Program 1: Text analyser

Laura types a sentence and the program counts its characters, letters, vowels (accented ones too), capitals, digits and spaces, writes it backwards and says whether it’s a palindrome (it reads the same both ways ignoring spaces and case). What makes it tricky: there are three different walks through the same sentence, and each one needs a different loop.

The idea

  1. Count: a for with an index from 0 to length() - 1. In each round, charAt(i) and an if chain that decides which counter goes up.
  2. Backwards: the same for, but starting at the end (length() - 1) and going down to 0 with i--.
  3. Palindrome: first build a “clean” version (letters only, lower case) with a for-each, because here you don’t need to know the position. Then, two indexes at once: i starts at the beginning, j at the end, and they are compared until they cross.

Before coding, write down the positions of a short word on paper (“Java”: J at 0, the last a at 3). What is length()? And the last position? That difference of one is the whole program.

The code

import java.util.Scanner;

/**
 * Text analyser: walks through a sentence character by character with an indexed for and with for-each,
 * counts what is in it and checks whether it is a palindrome by comparing from both ends.
 */
public class TextAnalyser {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("=== TEXT ANALYSER ===");
        System.out.print("Sentence: ");
        String sentence = sc.nextLine();

        // 1. Counters: they all start at 0 and each round adds where it belongs
        int letters = 0, vowels = 0, digits = 0, spaces = 0, capitals = 0;
        for (int i = 0; i < sentence.length(); i++) {        // < and not <=: the last position is length() - 1
            char c = sentence.charAt(i);
            if (Character.isLetter(c)) {
                letters++;
                if ("aeiouáéíóúAEIOUÁÉÍÓÚ".indexOf(c) >= 0) {   // is c in the list of vowels?
                    vowels++;
                }
                if (Character.isUpperCase(c)) {
                    capitals++;
                }
            } else if (Character.isDigit(c)) {
                digits++;
            } else if (c == ' ') {
                spaces++;
            }
        }
        System.out.println("Characters: " + sentence.length());
        System.out.println("Letters: " + letters + " (vowels: " + vowels + ", capitals: " + capitals + ")");
        System.out.println("Digits: " + digits + ", spaces: " + spaces);

        // 2. Reversed: walk from the last position down to 0
        String reversed = "";
        for (int i = sentence.length() - 1; i >= 0; i--) {
            reversed += sentence.charAt(i);
        }
        System.out.println("Reversed: " + reversed);

        // 3. Palindrome: first letters only, in lower case (for-each: the position isn't needed here)
        String clean = "";
        for (char c : sentence.toLowerCase().toCharArray()) {
            if (Character.isLetter(c)) {
                clean += c;
            }
        }
        // Two indexes moving closer: i from the start, j from the end. Reaching the middle is enough.
        boolean palindrome = true;
        int comparisons = 0;
        for (int i = 0, j = clean.length() - 1; i < j; i++, j--) {
            comparisons++;
            if (clean.charAt(i) != clean.charAt(j)) {
                palindrome = false;
                break;                                       // as soon as one pair fails, it isn't one
            }
        }
        System.out.println("Letters only: " + clean + " (" + clean.length() + ")");
        System.out.println("Palindrome? " + (palindrome ? "yes" : "no") + " (pairs compared: " + comparisons + ")");
        sc.close();
    }
}

Output

With the classic Spanish palindrome “Anita lava la tina” (“Anita washes the tub”):

=== TEXT ANALYSER ===
Sentence: Anita lava la tina
Characters: 18
Letters: 15 (vowels: 8, capitals: 1)
Digits: 0, spaces: 3
Reversed: anit al aval atinA
Letters only: anitalavalatina (15)
Palindrome? yes (pairs compared: 7)

And with a sentence from Laura with accents, capitals and numbers (“Laura passed FP2 in 2026”):

=== TEXT ANALYSER ===
Sentence: Laura aprobó FP2 en 2026
Characters: 24
Letters: 15 (vowels: 7, capitals: 3)
Digits: 5, spaces: 4
Reversed: 6202 ne 2PF óborpa aruaL
Letters only: lauraaprobófpen (15)
Palindrome? no (pairs compared: 1)

Let’s check the second one by hand. “Laura aprobó FP2 en 2026” has 24 characters. Letters: Laura (5) + aprobó (6) + FP (2) + en (2) = 15. Vowels: a, u, a, a, o, ó, e = 7 (the ó counts because it’s in the list). Capitals: L, F and P = 3. Digits: 2, 2, 0, 2 and 6 = 5. Spaces: 4. And 15 + 5 + 4 = 24: no character has gone uncounted. In the palindrome, the first pair already fails (l versus n), so break stops after a single comparison.

Questions you might ask

Why i < sentence.length() and not <=? Because positions start at 0. This short program does it with <= so you can see what happens:

public class OutOfRange {
    public static void main(String[] args) {
        String word = "Java";
        for (int i = 0; i <= word.length(); i++) {     // <= : one round too many
            System.out.println(i + ": " + word.charAt(i));
        }
        System.out.println("End");
    }
}

Real output:

0: J
1: a
2: v
3: a
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
        at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:55)
        at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:52)
        at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:213)
        at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:210)
        at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:98)
        at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106)
        at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302)
        at java.base/java.lang.String.checkIndex(String.java:4822)
        at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:46)
        at java.base/java.lang.String.charAt(String.java:1544)
        at OutOfRange.main(OutOfRange.java:5)

The four letters come out fine and in the fifth round, with i = 4, charAt(4) asks for a position that doesn’t exist. The message says it clearly: Index 4 out of bounds for length 4. The at java.base/… lines are the path inside Java; the one that matters is the last, OutOfRange.java:5, which points at your line. And notice that “End” is never printed.

The extra round of <=The letters J, a, v, a take positions 0 to 3; length() is 4. With i < 4 the loop does 4 rounds. With i <= 4 it does a fifth with i = 4, a position that does not exist, and charAt throws StringIndexOutOfBoundsException.word = "Java" length() = 4J0a1v2a34?indexi < word.length()i = 0, 1, 2, 3 → 4 roundsi <= word.length()i = 4 → charAt(4): exception
length() counts the letters, but the last position is length() – 1.

i <= text.length() when walking through a String (or anything that starts at 0). It compiles without warnings and fails in the last round. If the loop starts at 0, the condition is almost always <.

How does the palindrome loop work? Let’s zoom in on that piece:

// Two indexes moving closer: i from the start, j from the end. Reaching the middle is enough.
boolean palindrome = true;
int comparisons = 0;
for (int i = 0, j = clean.length() - 1; i < j; i++, j--) {
    comparisons++;
    if (clean.charAt(i) != clean.charAt(j)) {
        palindrome = false;
        break;                                    // as soon as one pair fails, it isn't one
    }
}

A for accepts two variables in its start (int i = 0, j = …) and two steps separated by a comma (i++, j--). With “anitalavalatina” (15 letters), the pairs are (0,14), (1,13)… up to (6,8): seven comparisons. Position 7, the v in the middle, is compared with nothing because when i is 7, j is 7 too and i < j is already false.

Two indexes moving towards each otherThe 15 letters of anitalavalatina with their positions. Each arc joins a pair that is compared: 0 with 14, 1 with 13, up to 6 with 8. Letter 7 stays in the middle. That is 7 comparisons and they all match.clean = "anitalavalatina" (15 letters)a0n1i2t3a4l5a6v7a8l9a10t11i12n13a147 pairs: (0,14) (1,13) … (6,8). Position 7 is the middle: it is compared with nobody.for (int i = 0, j = clean.length() – 1; i < j; i++, j–)
i moves forward and j moves back; the loop stops when they cross, halfway.
Roundijclean.charAt(i)clean.charAt(j)Equal?
1014aaYes
2113nnYes
3212iiYes
4311ttYes
5410aaYes
659llYes
768aaYes
(end)777 < 7 is false

Why for-each for the clean version and an indexed for for the rest? To clean you only need each letter, not its position: for-each is shorter and there’s no index to get wrong. To write backwards or compare two positions you do need the index. The rule: do you need to know where you are? Index. Only what’s there? for-each.

Is adding letters to a String with += efficient? For one sentence, more than enough. Each += creates a new String, so with a text of thousands of characters you’d notice; that’s what StringBuilder is for, which you’ll see in the Strings topic.

"aeiouáéíóúAEIOUÁÉÍÓÚ".indexOf(c) >= 0 is a short way of asking “is c in this list?” without writing ten comparisons with ||.

Try it yourself

  • Count the words too: they are the spaces + 1… unless the sentence has double spaces or starts with one. How would you fix that?
  • Change the clean sentence so it keeps the digits and try “2002”: is it a palindrome?

Program 2: Guess the number with while

In the flow control practice the guessing game had three attempts and the same block copied three times. Now we write it once inside a while and give 7 attempts. The secret is the same (seed 42, number 31) so you can compare. Two new rules: out-of-range numbers don’t use up an attempt, and on a hit you get a rating depending on the attempts used.

The idea

  • A counter (attempts) that only goes up with valid attempts.
  • A flag (guessed) that starts as false and becomes true on a hit.
  • The while condition combines both: keep going while there are attempts left and you haven’t guessed: attempts < MAX && !guessed.
  • For out-of-range numbers, continue: back to the condition without reaching attempts++.
  • When leaving the loop there are two possible reasons; the flag says which one.

Before coding, answer: when must the loop end? Write down both situations (“they guessed it” or “no attempts left”) and negate them to get the condition for carrying on. That’s De Morgan: not (A or B) = not A and not B.

The code

import java.util.Random;
import java.util.Scanner;

/**
 * Guess the number, now with while: the block is written ONCE and repeated
 * until you get it or use up the 7 attempts. Same secret as in Flow control (seed 42).
 */
public class Guess {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Random random = new Random(42);
        int secret = random.nextInt(100) + 1;
        final int MAX = 7;                        // with 7 attempts and halving, you always get it

        System.out.println("=== GUESS THE NUMBER (1-100) ===");
        System.out.println("You have " + MAX + " attempts. Out-of-range numbers don't count.");

        int attempts = 0;                         // counter: how many valid attempts so far
        boolean guessed = false;                  // flag: have you guessed it yet?
        while (attempts < MAX && !guessed) {      // carry on while there are attempts left AND you haven't guessed it
            System.out.print("Attempt " + (attempts + 1) + ": ");
            int n = sc.nextInt();
            if (n < 1 || n > 100) {
                System.out.println("Out of range: it doesn't count.");
                continue;                         // back to the condition without counting the attempt
            }
            attempts++;                           // only valid attempts get here
            if (n == secret) {
                guessed = true;                   // the while condition will be false at the next check
            } else if (n < secret) {
                System.out.println("Higher.");
            } else {
                System.out.println("Lower.");
            }
        }

        // There are two possible reasons for leaving the while: the flag says which one
        if (guessed) {
            String level = attempts <= 3 ? "Ace!" : (attempts <= 5 ? "Well played." : "Just in time.");
            System.out.println("It was " + secret + ". You guessed it in " + attempts + " attempts. " + level);
        } else {
            System.out.println("No attempts left. It was " + secret + ".");
        }
        sc.close();
    }
}

Output

A game with an out-of-range number in the middle:

=== GUESS THE NUMBER (1-100) ===
You have 7 attempts. Out-of-range numbers don't count.
Attempt 1: 50
Lower.
Attempt 2: 25
Higher.
Attempt 3: 150
Out of range: it doesn't count.
Attempt 3: 37
Lower.
Attempt 4: 31
It was 31. You guessed it in 4 attempts. Well played.

Notice that “Attempt 3” appears twice: 150 didn’t count, so the next one is still the third. The diagram separates rounds from attempts:

Rounds versus attemptsTrace of the game 50, 25, 150, 37, 31. 150 is out of range: continue goes back to the condition without adding the attempt, so there are 5 rounds and 4 attempts. When 31 is typed the guessed flag becomes true and the while ends.while (attempts < MAX && !guessed) · secret = 31roundtypedattempts++attemptswhat happens150yes1Lower.225yes2Higher.3150no (skipped)2continue437yes3Lower.531yes4guessed = true5 rounds of the while, 4 attempts: 150 goes back to the condition without reaching attempts++.
continue does not end the loop: it skips the rest of that round.

And a lost game, going up ten at a time:

=== GUESS THE NUMBER (1-100) ===
You have 7 attempts. Out-of-range numbers don't count.
Attempt 1: 10
Higher.
Attempt 2: 20
Higher.
Attempt 3: 30
Higher.
Attempt 4: 40
Lower.
Attempt 5: 45
Lower.
Attempt 6: 50
Lower.
Attempt 7: 60
Lower.
No attempts left. It was 31.

After the seventh valid attempt, attempts < MAX is 7 < 7, false: the while ends with guessed still false and the losing message is printed.

Questions you might ask

Why a flag and not break on a hit? Both work. With break, the while condition would only say attempts < MAX and the reason for leaving would be hidden inside the body. With the flag, the condition says exactly when you play: “there are attempts left and you haven’t guessed”. And after the loop, the flag tells you why it ended without you having to guess.

What exactly does continue do here? It skips the rest of that round and evaluates the condition again. Since attempts++ comes after the continue, 150 doesn’t use up an attempt. Careful: if attempts++ were before the range if, 150 would count.

Why 7 attempts? Because with “halving” (50, then 25 or 75…) each attempt rules out half of the remaining numbers: 100 → 50 → 25 → 13 → 7 → 4 → 2 → 1. In 7 attempts you always get down to one (2⁷ = 128, more than 100). In the lost game there was no halving, and it shows.

Why the nested ternary for the rating? attempts <= 3 ? "Ace!" : (attempts <= 5 ? "Well played." : "Just in time.") is an if/else if/else that returns a text. With 4 attempts, the first condition is false and the second true: “Well played.”. If it’s hard to read, write it with if; the result is the same.

And compared with the version without loops? That one had three copies of about 12 lines and only 3 attempts. This one has one block and 7 attempts; for 20, you change one number: MAX = 20.

Putting attempts++ in the wrong place. Before the continue, out-of-range numbers use up an attempt; outside the while (or missing), attempts < MAX is always true and the loop only ends if you guess. Before running, ask yourself: which variable in the condition changes in every round?

Try it yourself

  • Remove the seed (new Random()) and play several games halving each time: do you ever need more than 7?
  • Rewrite the loop with while (true) and break on a hit or when the attempts run out. Which one reads better?

Program 3: Pattern generator with validation

A menu draws three patterns of size n (from 1 to 9): a triangle of asterisks, a hollow frame and a chessboard. The menu repeats until 0 is chosen. What makes it tricky: there are three loops at once (the menu’s, the rows’ and the columns’) and break and continue inside a do-while.

The idea

  • The menu is a do-while: it has to be shown at least once, before you know which option is chosen.
  • Option 0 leaves with break. Invalid options and sizes use continue to go back to the menu.
  • Each pattern is two nested loops: the outer one does one round per row and the inner one, one round per column of that row. The only thing that changes between patterns is what gets written in each square (row, col).

Before coding, draw the size-4 pattern on a grid with rows and columns numbered from 1. What do the squares with an asterisk have in common? In the triangle, col <= row; in the frame, being in the first or last row or column.

The code

import java.util.Scanner;

/**
 * Pattern generator: a menu with do-while (it is shown at least once) and nested loops:
 * the outer one walks through the rows and the inner one, the columns of each row.
 */
public class PatternGenerator {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int option;
        do {
            System.out.println();
            System.out.println("=== PATTERN GENERATOR ===");
            System.out.println("1. Triangle   2. Frame   3. Board   0. Exit");
            System.out.print("Option: ");
            option = sc.nextInt();
            if (option == 0) {
                break;                             // leaves the do-while without asking for a size
            }
            if (option < 1 || option > 3) {
                System.out.println("Invalid option.");
                continue;                          // in a do-while, continue jumps to the condition at the end
            }
            System.out.print("Size (1-9): ");
            int n = sc.nextInt();
            if (n < 1 || n > 9) {
                System.out.println("Invalid size.");
                continue;
            }

            for (int row = 1; row <= n; row++) {             // one round per row
                String line = "";
                for (int col = 1; col <= n; col++) {         // one round per column, in every row
                    if (option == 1) {
                        line += (col <= row) ? "* " : "";  // row 1 has 1 asterisk, row 2 has 2...
                    } else if (option == 2) {
                        boolean edge = row == 1 || row == n || col == 1 || col == n;
                        line += edge ? "# " : "  ";          // inside the frame, spaces
                    } else {
                        line += ((row + col) % 2 == 0) ? "# " : ". ";   // even sum: dark square
                    }
                }
                System.out.println(line.stripTrailing());     // removes the extra space at the end
            }
        } while (option != 0);
        System.out.println("Goodbye.");
        sc.close();
    }
}

Output

A full session: a triangle of 4, a board of 5, an invalid size, a frame of 4, an option that doesn’t exist and exit.

=== PATTERN GENERATOR ===
1. Triangle   2. Frame   3. Board   0. Exit
Option: 1
Size (1-9): 4
*
* *
* * *
* * * *

=== PATTERN GENERATOR ===
1. Triangle   2. Frame   3. Board   0. Exit
Option: 3
Size (1-9): 5
# . # . #
. # . # .
# . # . #
. # . # .
# . # . #

=== PATTERN GENERATOR ===
1. Triangle   2. Frame   3. Board   0. Exit
Option: 2
Size (1-9): 12
Invalid size.

=== PATTERN GENERATOR ===
1. Triangle   2. Frame   3. Board   0. Exit
Option: 2
Size (1-9): 4
# # # #
#     #
#     #
# # # #

=== PATTERN GENERATOR ===
1. Triangle   2. Frame   3. Board   0. Exit
Option: 7
Invalid option.

=== PATTERN GENERATOR ===
1. Triangle   2. Frame   3. Board   0. Exit
Option: 0
Goodbye.

Let’s check the board: in row 1, column 1, 1 + 1 = 2 is even, so #; in row 1, column 2, 1 + 2 = 3 is odd, .. Going down a row flips the parity of the sum, which is why each row starts the opposite way from the one above.

Questions you might ask

How many times does the inner line run? For a size n, the outer loop does n rounds and, in each one, the inner loop does another n: n × n. With the board of 5, 25 squares. This zoom is the heart of the program:

for (int row = 1; row <= n; row++) {             // one round per row
    String line = "";
    for (int col = 1; col <= n; col++) {         // one round per column, in every row
        if (option == 1) {
            line += (col <= row) ? "* " : "";  // row 1 has 1 asterisk, row 2 has 2...
        } else if (option == 2) {
            boolean edge = row == 1 || row == n || col == 1 || col == n;
            line += edge ? "# " : "  ";          // inside the frame, spaces
        } else {
            line += ((row + col) % 2 == 0) ? "# " : ". ";   // even sum: dark square
        }
    }
    System.out.println(line.stripTrailing());     // removes the extra space at the end
rowcol goes throughcol <= row in…Triangle line
11, 2, 3, 41*
21, 2, 3, 41, 2* *
31, 2, 3, 41, 2, 3* * *
41, 2, 3, 41, 2, 3, 4* * * *

Why is line declared inside the outer loop? Because each row starts empty. If it were outside, row 2 would be written glued onto row 1 and the triangle would turn into a single line that keeps growing.

What does continue do inside a do-while? It jumps to the condition at the end (while (option != 0)), not to the start of the body. With size 12, option is 2: the condition is true and the menu comes up again. That’s why it works without asking for anything else.

And why does 0 leave with break rather than waiting for the condition? Because after reading the option comes the size question. Without the break, choosing 0 would make the program ask “Size (1-9):” before leaving. The break stops it right there.

What’s stripTrailing() for? Each square adds its character plus a space, so every line ends in a space you can’t see but is there. stripTrailing() removes it before printing.

Using the same variable in both loops (for (int i…) inside another for (int i…)). Java won’t compile it: variable i is already defined in method main(String[]). Use names that say what they walk through: row and col.

Try it yourself

  • Add option 4, an upside-down triangle (row 1 with n asterisks). Hint: change a single condition.
  • Count in a variable how many # have been drawn in the whole session and print it when leaving.

Common mistakes in this practice

  • <= instead of < when walking through a text. One round too many and a StringIndexOutOfBoundsException.
  • A loop whose condition never changes. If no variable in the condition changes inside the body, the loop doesn’t end.
  • continue before updating the counter. The round skips the line that made the loop move on.
  • Declaring the accumulator in the wrong place. Inside the loop it resets every round; outside, it drags from one row to the next.
  • Mixing up break and continue. The first ends the loop; the second only the current round.
  • The same name in two nested loops. It doesn’t compile; and if you dodge it with another block, you’ll struggle to know what each one walks through.

Watch it step by step in Python Tutor

Python Tutor (pythontutor.com) runs code line by line and draws the variables. Choose Java in the drop-down and paste this program, a 3-row triangle with a counter for the rounds of the inner loop:

public class TutorNested {
    public static void main(String[] args) {
        int innerRounds = 0;
        for (int row = 1; row <= 3; row++) {
            String line = "";
            for (int col = 1; col <= row; col++) {
                line += "*";
                innerRounds++;
            }
            System.out.println(line);
        }
        System.out.println("Rounds of the inner loop: " + innerRounds);
    }
}

Output:

*
**
***
Rounds of the inner loop: 6

What to watch step by step:

  1. Every time it enters the inner loop, col goes back to 1: the inner for is created again for each row.
  2. In row 1 the inner loop does 1 round; in row 2, two; in row 3, three. Watch line grow and reset to "" when the row changes.
  3. innerRounds never resets (it’s outside both loops): it ends at 1 + 2 + 3 = 6.
  4. Look at the last step of each loop: the condition is evaluated once more than the body (with col = 2 in row 1, 2 <= 1 is false and it leaves).

Summary and next step

  • To walk through a text with an index: for (int i = 0; i < text.length(); i++). The last position is length() - 1.
  • To walk backwards: start at length() - 1 and go down with i-- while i >= 0.
  • Two indexes moving closer (i++, j-- while i < j) compare a text with itself in half the rounds.
  • A while with a counter and a flag (attempts < MAX && !guessed) says in its condition exactly when to carry on.
  • continue jumps to the next check of the condition; in a do-while, to the one at the end.
  • In nested loops, the inner line runs (outer rounds) × (inner rounds) times.

Checklist: have you practised it?

  • Have you run the three programs and checked the outputs?
  • Can you explain why i <= text.length() fails in the last round?
  • Could you say how many comparisons the palindrome check makes with a 9-letter word?
  • Do you know where attempts++ has to go so that out-of-range numbers don’t count?
  • Have you tried the “Try it yourself” sections without looking at the theory?

If you answered yes to almost everything, you’re ready for the Java loops exercises, where I no longer give you the code. See you there!

Next step: exercisesLoops in Java — exercises with vowels, grades up to -1 and primes in a range (and the loop that once froze on me)

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