while, for, and Nested Loops

The while loop and the infinite loop that lurks beside it, the increment and decrement operators, the for loop that puts all the control in one line, nested loops, and characters — plus the rule for choosing between the two kinds of loop. Follows Think Java 2e, Chapter 6 (Loops and Strings), Sections 6.1-6.6, pp. 89-98, cross-referenced against The Java Tutorials — The for Statement.

Subject: Java · 65 slides · code lesson

Open the interactive version of this deck

What this lesson covers

The lesson, slide by slide

1. while, for, and Nested Loops

Title

Think Java 2e · Chapter 6 · Loops and Strings

Sections 6.1-6.6 · pp. 89-98

2. What you will be able to do

Objectives

This lesson follows Think Java 2e, Chapter 6 (Loops and Strings), Sections 6.1-6.6, pp. 89-98. Everything on these slides can be checked against those pages.

1. Write a while loop and trace it, and say what makes a loop terminate.

2. Recognise an infinite loop and name the missing piece that causes it.

3. Use ++, --, += and -= correctly.

4. Write a for loop, naming its initializer, condition and update.

5. Explain the scope of a variable declared in a for loop's initializer.

6. Trace a nested loop and say how many times the inner body runs.

7. Choose between for and while by asking whether the number of repetitions is known in advance.

3. Retrieve before you read

Warm-up

The list from Lesson 1a is almost complete.

Discussion prompt

Name the five basic instructions that appear in every programming language. Which one have you still not met — and what would a program need it for?

Hint: Input, output, math, decision, and one more.

Answer:

Repetition is the last one. You have written input, output, math and — since Chapter 5 — decision.

Computers are often used to automate repetitive tasks, such as searching for text in documents. Repeating tasks without making errors is something computers do well and people do poorly, which is why this instruction exists at all.

4. The last of the five instructions

Concept

A loop runs the same statements over and over until a condition becomes false. That is the whole idea, and everything in this lesson is about writing it clearly and making sure it stops.

Figure (svg): A flowchart for a while loop, showing the condition tested, the body executed, and an arrow looping back to the test

Downey & Mayfield, Think Java, 2nd edition (Green Tea Press / O'Reilly, 2020) — Think Java 2e, Chapter 6 (Loops and Strings), Sections 6.1-6.6, pp. 89-98 — Chapter 6 opens on printed page 89.

5. The while statement

Section

Section 6.1

6. Repeat while a condition holds

Concept

Using a while statement we can repeat the same code multiple times. Read it in English: start with n set to 3. While n is greater than 0, print the value of n and reduce it by 1. When you get to 0, print Blastoff!

int n = 3;
while (n > 0) {
    System.out.println(n);
    n = n - 1;
}
System.out.println("Blastoff!");
n at the testconditionbody runs?output
33 > 0 trueyes3
22 > 0 trueyes2
11 > 0 trueyes1
00 > 0 falseno — the loop endsBlastoff!

loop — A statement that executes a sequence of statements repeatedly.

loop body — The statements inside the loop.

Note the last row. The condition is checked before each pass, so when n reaches 0 the body does not run again — and the loop leaves n at 0 rather than -1.

7. The three steps of a while loop

Notation

The flow of execution is short enough to memorise, and worth memorising because every loop you write follows it.

Annotate

  • Step 1 happens first, before the body has run even once. So a loop whose condition is false at the start runs its body zero times — which is legal and sometimes exactly what you want.
  • Step 3 is what makes it a loop: the last step loops back around to the first. Everything else in the construct is an ordinary conditional.
  • The body must change something the condition depends on. Otherwise the condition can never become false, and the loop repeats forever.
  • The check happens between passes, not during one. If the body changes n three times, only the value at the end of the body is tested.

Compare this against the if statement from Chapter 5. The only difference is step 3 — an if runs its block at most once, and a while goes back to the test.

8. Tracing a countdown by hand

Worked example

A loop trace is a table with one row per pass. Building one is how you check a loop without running it.

int n = 3;
while (n > 0) {
    System.out.println(n);
    n = n - 1;
}
System.out.println("Blastoff!");
passn at the topprintedn after the body
1332
2221
3110
40(condition false — no body)0

Write the variable's starting value.

Why: n is 3, set before the loop begins.

For each pass, test the condition first.

Why: The test uses the value in the column at the top of the row.

If it holds, run the body and record the new value.

Why: Printing does not change n; the assignment does.

Stop when the condition fails.

Why: The fourth row has no body — the loop exits and execution continues after the closing brace.

Verify: Expect 3, 2, 1, Blastoff! — four lines.

Why: Then check the count: the body ran three times and printed three numbers. If you predicted four numbers, you probably tested the condition after the body rather than before it.

9. How many lines does this print?

Prediction

Count the passes, not the values.

int n = 5;
while (n > 2) {
    System.out.println(n);
    n = n - 1;
}
n at the testruns?printed
5yes5
4yes4
3yes3
2no—

Predict first

How many numbers are printed?

  • 3
  • 4
  • 5
  • 2

Correct: 3

Why: The body runs while n is strictly greater than 2, so it runs for 5, 4 and 3 and stops when n reaches 2. Counting passes rather than reading the numbers is the reliable method — the values printed and the number of passes are different questions.

10. Infinite loops, and the ones nobody can settle

Concept

The body should change one or more variables so that eventually the condition becomes false. Otherwise the loop repeats forever — an infinite loop.

int n = 3;
while (n > 0) {
    System.out.println(n);
    // n never changes
}
passnconditionwill it ever end?
13trueno
23trueno
...3trueno

infinite loop — A loop whose condition is always true.

This prints 3 forever, or at least until you terminate the program. An endless source of amusement for computer scientists is the observation that the directions on shampoo — lather, rinse, repeat — are an infinite loop.

11. A loop whose termination nobody has proved

Trap

The trap

This looks like an infinite loop and may not be. n sometimes increases and sometimes decreases.

int n = 3;
while (n != 1) {
    System.out.println(n);
    if (n % 2 == 0) {          // n is even
        n = n / 2;
    } else {                   // n is odd
        n = 3 * n + 1;
    }
}
neven or oddnext n
3odd3 * 3 + 1 = 10
10even10 / 2 = 5
5odd16
16, 8, 4, 2even each timehalved to 1 — the loop ends

Starting at 3 the sequence is 3, 10, 5, 16, 8, 4, 2 and then stops. The code will not print 1, because the loop terminates as soon as n equals 1.

The fix

The honest position: for some starting values you can prove it terminates; in general nobody knows.

// powers of two obviously terminate:
//   16 -> 8 -> 4 -> 2 -> 1
// but does EVERY starting value reach 1?
// No one has proved it or disproved it.
questionanswer
does it terminate for n = 16?yes, provably — repeated halving
does it terminate for n = 27?yes, after 111 steps — checked by running it
does it terminate for every n?unknown — this is the Collatz conjecture

The lesson is not about number theory. It is that you cannot always tell by looking whether a loop terminates — so a loop whose variable does not move steadily toward its exit condition deserves real scrutiny.

12. Why does this never stop?

Error analysis

Three loops, each infinite for a different reason.

Annotate

  • A: the body changes nothing. n stays 3, so the condition stays true forever. This is the commonest form — the update was simply forgotten.
  • B: the update moves the wrong way. i starts at 0 and decreases, so i < 10 becomes more true rather than less. The update exists but has the wrong sign.
  • C: the variable steps over the exit value. k takes the values 1, 3, 5, 7, 9, 11 and never equals 10 exactly. The update is right and the CONDITION is too strict.
  • The fix for C is k < 10 rather than k != 10. Testing for an exact value is fragile whenever the step size is not 1 — a comparison is almost always safer.
  • Three separate failure modes: no update, an update in the wrong direction, and a condition the variable can jump past. Checking all three is a good habit before running any loop.

If a program appears to hang, an infinite loop is the first thing to suspect — and these three questions will usually find it.

13. Why is the condition tested before the body?

Socratic

It could have been tested afterwards.

Discussion prompt

A while loop checks its condition before running the body, so a loop whose condition starts false runs zero times. When would that be exactly the behaviour you want — and what would break if the check came after the first pass instead?

Hint: Think about processing a list that might be empty.

Answer:

Running zero times is essential whenever the work might not be needed: reading input until there is none left, when there was none to begin with; processing every character of a string, when the string is empty.

If the check came after the body, every such loop would do one pass on nothing — reading an item that is not there, or indexing past the end of an empty string. Testing first is what makes a loop safe on an empty case, and empty cases are extremely common.

Java does have a do-while loop that tests afterwards and therefore always runs at least once. It is used far less often, for exactly this reason.

14. Complete the countdown

Fill the middle

Print 10 down to 1.

Fill in the blanks

int n = 10;
while (n > 0) -} 1;
}

Why: n > 0 keeps the body running while n is 10 down to 1 and stops at 0, and subtracting 1 each pass is what moves n toward that exit. Using >= would print 0 as well, and forgetting the subtraction would give an infinite loop.

15. Increment and decrement

Section

Section 6.2

16. Concise ways to add and subtract

Concept

Assignments like i = i + 1 do not often appear in loops, because Java provides a more concise way. ++ is the increment operator and -- is the decrement operator.

int i = 1;
while (i <= 5) {
    System.out.println(i);
    i++;              // add 1 to i
}
writtensame asmeaning
i++i = i + 1increment
i--i = i - 1decrement
i += 2i = i + 2add 2
i -= 2i = i - 2subtract 2

increment — Increase the value of a variable.

decrement — Decrease the value of a variable.

If you want to change a variable by an amount other than 1, use += and -=. These are not new operations — every one of them is an assignment written more briefly.

17. The 2-4-6-8 loop

Picture it

A loop that steps by 2 rather than 1, using the compound assignment operator.

Figure (svg): A trace strip showing i taking the values 2, 4, 6 and 8 and then failing the condition at 10

The output is 2, 4, 6, 8, Who do we appreciate? — four passes, and then the condition fails at 10. Note that i finishes at 10, one step past the last value used.

18. Rewriting a loop with the concise operators

Worked example

Take a loop written with full assignments and shorten it, checking that nothing about its behaviour changes.

// before
int i = 1;
while (i <= 5) {
    System.out.println(i);
    i = i + 1;
}

// after
int i = 1;
while (i <= 5) {
    System.out.println(i);
    i++;
}
passi printedi after
112
223
334
445
556 — condition now false

Identify the update statement.

Why: i = i + 1 at the end of the body.

Replace it with the increment operator.

Why: i++ does exactly the same thing.

Confirm the trace is unchanged.

Why: Five passes printing 1 to 5, and i finishing at 6.

Note what has NOT changed.

Why: The condition, the starting value and the number of passes are all the same. Only the notation is shorter.

Verify: Both versions print 1 through 5 on separate lines.

Why: Then check the final value of i by printing it after the loop: 6 in both cases. A loop variable almost always ends one step past the last value it took, and knowing that prevents a lot of confusion.

19. What is i after this loop?

Prediction

The loop variable's final value is often needed and often mispredicted.

int i = 0;
while (i < 3) {
    System.out.println(i);
    i++;
}
System.out.println("i is now " + i);
passi printedi after
101
212
323
—condition fails3

Predict first

What is the last line of output?

  • i is now 3
  • i is now 2
  • i is now 4
  • i is now 0

Correct: i is now 3

Why: The loop prints 0, 1 and 2, and the increment after the last pass takes i to 3 — which is what fails the condition and ends the loop. A loop variable finishes one step past the last value the body used, which is exactly why i < 3 gives three passes starting from zero.

20. Why the concise forms are worth using

Concept

i++ saves four characters over i = i + 1. That is not the argument for it.

formhow many times is the variable named?risk
i = i + 1twiceyou can mistype one of them
i++oncenone of that kind
count = count + 1twicein a long name, a typo is easy to miss
count++once—

The real benefit is naming the variable once. total = totl + 1 compiles if totl happens to exist, and is a genuinely nasty bug; total++ cannot go wrong that way. It is the same argument as returning a condition instead of true-or-false in Lesson 5b: prefer the form with fewer places to be wrong.

21. Using i++ where you meant to change something else

Trap

The trap

The update increments the wrong variable. The loop never ends.

int i = 0;
int total = 0;
while (i < 5) {
    total += i;
    total++;          // meant i++
}
passitotalcondition
101still true
202still true
...0growingtrue forever

i never changes, so i < 5 is always true. The program appears to hang, and the mistake is one character away from a correct loop.

The fix

The update must change the variable the condition tests.

int i = 0;
int total = 0;
while (i < 5) {
    total += i;
    i++;
}
passitotal after
100
211
323
436
5410 — then i becomes 5 and the loop ends

The check to run on every loop you write: name the variable in the condition, then find the statement that changes it. If you cannot point at one, the loop does not terminate.

22. Match the shorthand to what it does

Matching

Four compound operators.

Match the pairs

  • a. i++
  • b. i--
  • c. i += 5
  • d. i -= 2
  • r1. i = i + 1
  • r2. i = i - 1
  • r3. i = i + 5
  • r4. i = i - 2

Why: Every one of these is an assignment written more briefly — nothing new is happening. ++ and -- change by exactly one, while += and -= take an amount, so i++ and i += 1 are the same thing.

23. Step by three

Fill the middle

Print 0, 3, 6, 9.

Fill in the blanks

int i = 0;
while (i <= 9) +=} 3;
}

Why: <= is needed so that 9 itself is printed — with < the loop would stop at 6. += 3 steps by three each pass. Note that != 10 would be a disaster here: i takes the values 0, 3, 6, 9, 12 and never equals 10, giving an infinite loop.

24. Does i++ ever differ from i = i + 1?

Edge cases

They are described as having the same effect. Push on that.

Discussion prompt

As a statement on its own, i++ and i = i + 1 are identical. Can you think of a context where the two forms might not be interchangeable? What does that suggest about writing i++ inside a larger expression?

Hint: What value does the expression i++ itself have?

Answer:

i++ is an expression as well as a statement, and its value is the value of i before the increment. So int j = i++; gives j the old value, while int j = ++i; gives it the new one.

That distinction is a well-known source of confusing code, and Think Java sensibly does not dwell on it. The practical advice: use i++ as a statement on its own line, and never inside a larger expression. Code that depends on which form you used is code that will be misread.

25. The for statement

Section

Section 6.3

26. Initializer, condition, update — all in one line

Concept

The loops so far have three parts in common: they initialise a variable, they have a condition depending on it, and they update it inside the body. Running the same code multiple times is called iteration, and it is common enough that Java has a statement expressing it more concisely.

for (int i = 2; i <= 8; i += 2) {
    System.out.print(i + ", ");
}
System.out.println("Who do we appreciate?");
partrunsequivalent in a while loop
int i = 2once, at the very beginningthe line before the while
i <= 8each time through, before the bodythe while condition
i += 2at the end of each iterationthe last statement in the body

iteration — Executing a sequence of statements repeatedly.

loop variable — A variable that is initialised, tested and updated in order to control a loop.

The for loop is often easier to read because it puts all the loop-related statements at the top, which lets you focus on the statements inside the body.

27. The order the three parts run in

Picture it

They are written left to right and they do not run in that order after the first pass. The update comes at the end of each iteration.

Figure (svg): A flowchart for a for loop showing initialisation once, then repeated condition, body and update

So the sequence is: initialise, test, body, update, test, body, update, ... and the loop ends at a test. The update runs after every body, including the last one — which is why the loop variable finishes past the end.

28. Converting a while loop to a for loop

Worked example

Any for loop can be rewritten as a while loop and vice versa. Doing the conversion once makes the three parts unmistakable.

// while
int i = 2;
while (i <= 8) {
    System.out.print(i + ", ");
    i += 2;
}

// for
for (int i = 2; i <= 8; i += 2) {
    System.out.print(i + ", ");
}
partin the while versionin the for version
initializerthe line above the loopfirst slot in the parentheses
conditionin the while parenthesessecond slot
updatethe last line of the bodythird slot
the actual workthe rest of the bodythe whole body

Find the three loop-control pieces in the while version.

Why: Initialisation above, condition in the parentheses, update at the bottom of the body.

Move them into the for header, separated by semicolons.

Why: Note that the separators are semicolons, not commas.

Leave only the real work in the body.

Why: The body now contains nothing about controlling the loop.

Check the trace is identical.

Why: Four passes printing 2, 4, 6 and 8.

Verify: Both versions print 2, 4, 6, 8, Who do we appreciate?

Why: The benefit is visible immediately: in the for version the body is one line and it is the line that does the work. Everything about how many times it runs is in one place, where it can be checked at a glance.

29. How many times does the body run?

Prediction

Count from the header alone.

for (int i = 0; i < 5; i++) {
    System.out.println("hello");
}
iconditionbody runs?
0, 1, 2, 3, 4trueyes — five times
55 < 5 is falseno

Predict first

How many times is 'hello' printed?

  • 5
  • 4
  • 6
  • infinite

Correct: 5

Why: i takes the values 0, 1, 2, 3 and 4 — five values — before reaching 5 and failing the condition. The pattern for (int i = 0; i < n; i++) runs exactly n times, and it is worth learning as a unit because it is the most common loop in all of Java.

30. A variable declared in the initializer is local to the loop

Concept

There is one real difference between the two forms. If you declare a variable in the initializer, it exists only inside the for loop.

for (int n = 3; n > 0; n--) {
    System.out.println(n);
}
System.out.println("n is now " + n);      // compiler error

// declare it outside if you need it afterwards:
int n;
for (n = 3; n > 0; n--) {
    System.out.println(n);
}
System.out.println("n is now " + n);      // fine
declaredusable inside the loop?usable after it?
for (int n = 3; ...)yesno — cannot find symbol
int n; then for (n = 3; ...)yesyes

Notice that the second version's for statement does not say int n = 3 — it simply initialises the existing variable. This is Lesson 4a's scope idea again: a variable lives in the block that declares it.

31. Commas instead of semicolons

Trap

The trap

The separators inside a for header are semicolons. Commas do not compile.

for (int i = 0, i < 5, i++) {     // syntax error
    System.out.println(i);
}
what Java expectswhat it found
initializer ; condition ; updatethree items separated by commas
a semicolon after the initializera comma
result';' expected

The mistake is understandable — three items in parentheses look like arguments, which are comma-separated. But these are three separate statements, and statements are separated by semicolons.

The fix

Semicolons, because each part is a statement rather than an argument.

for (int i = 0; i < 5; i++) {
    System.out.println(i);
}
slotcontainskind of thing
1int i = 0a declaration and assignment
2i < 5a boolean expression
3i++an assignment

Reading the header as three statements, not three arguments also explains why the middle one must be a boolean and the other two need not be — they are doing different jobs.

32. Which slot does each piece go in?

Definition probe

Three slots, separated by semicolons.

Sort into buckets

Sort each piece of a for header.

the initializer
int i = 0; char c = 'A'
the condition
i < names.length; c <= 'Z'
the update
i++
init
Runs once at the very beginning, and usually declares and sets the loop variable.
cond
A boolean expression, checked before every pass including the first. When it is false the loop ends.
upd
Runs at the end of each iteration, moving the loop variable toward the value that will end the loop.

33. Does this compile?

Prediction

The loop variable is used after the loop.

for (int n = 3; n > 0; n--) {
    System.out.println(n);
}
System.out.println("n is now " + n);
where n is declaredwhere it exists
in the initializerinside the for loop only
the line after the loopoutside — n does not exist there

Predict first

What happens?

  • A compile error — n does not exist outside the loop
  • It prints 'n is now 0'
  • It prints 'n is now 3'
  • It compiles but prints nothing

Correct: A compile error — n does not exist outside the loop

Why: A variable declared in a for loop's initializer exists only inside that loop, so the last line reports 'cannot find symbol'. To use the value afterwards you must declare the variable before the loop and write for (n = 3; ...) with no type in the initializer.

34. for or while

Trade off

Fill the blanks from what the two forms make easy.

Comparison matrix

forwhile
where the loop control livesall three parts in the headerspread over three places
the loop variable's scopelocal to the loop, if declared in the initializerwhatever block declared it
best whenyou know how many repetitionsyou do not know how many

The last row is the rule from Section 6.6, and it is the one worth remembering: definite counting takes a for, indefinite waiting takes a while.

35. Nested loops

Section

Section 6.4

36. A loop inside a loop

Concept

Like conditional statements, loops can be nested one inside the other. Nested loops let you iterate over two variables — for example, to generate a multiplication table.

for (int x = 1; x <= 10; x++) {
    for (int y = 1; y <= 10; y++) {
        System.out.printf("%4d", x * y);
    }
    System.out.println();
}
loopcallediterateshow many times in total
for xthe outer loop1 to 10, once10
for ythe inner loop1 to 10, for each x100
printf—inside the inner loop100
println()—inside the outer loop10 — one newline per row

The outer loop iterates from 1 to 10 only once, but the inner loop iterates from 1 to 10 each of those ten times. As a result printf is invoked 100 times.

37. Row by row

Picture it

It is important to realise that the output is displayed row by row. The inner loop displays a single row; the outer loop iterates over the rows themselves.

Figure (svg): A grid showing the first four rows and columns of a multiplication table with row and column indices

Another way to read nested loops is: for each row x, and for each column y, ... — which is exactly how you would describe filling in the table by hand.

38. Where the newline goes

Worked example

The single most important detail in a nested printing loop is which loop the println() belongs to. Moving it one level changes the entire output.

for (int x = 1; x <= 3; x++) {
    for (int y = 1; y <= 3; y++) {
        System.out.printf("%4d", x * y);
    }
    System.out.println();          // inside the OUTER loop
}
where println() isruns how oftenoutput shape
inside the outer loop, after the inner3 times — once per rowa 3 by 3 grid
inside the inner loop9 timesone number per line
after both loopsonceall nine numbers on one line

Put the printf inside the inner loop.

Why: It produces one cell, and %4d pads it to four characters wide so the columns line up.

Put the println after the inner loop but inside the outer one.

Why: It ends the row, and runs once per value of x.

Check the counts.

Why: printf 9 times, println 3 times — the ratio is the inner loop's length.

Try moving the println and predict first.

Why: Inside the inner loop, every number gets its own line. Outside both, there are no line breaks at all.

Verify: Expect three rows of three numbers, aligned in columns.

Why: The alignment is worth noticing: %4d displays the value padded with spaces to four characters, so the output lines up vertically regardless of how many digits each number has.

39. How many times does the inner body run?

Prediction

Multiply.

for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 3; j++) {
        System.out.print("*");
    }
}
looppasses
outer4
inner, each time3
total12

Predict first

How many asterisks are printed?

  • 12
  • 7
  • 4
  • 3

Correct: 12

Why: The outer loop runs 4 times and the inner loop runs 3 times for each of them, so the inner body runs 4 times 3, which is 12. Nested loops multiply rather than add — adding would be the count for two loops written one after the other.

40. Counting the passes of a nested loop

Concept

Nested loops multiply. That is obvious once stated and routinely underestimated when it matters.

outer runsinner runs each timebody of the inner loop runs
1010100
10010010,000
1,0001,0001,000,000
nnn squared

The last row is the one to carry forward. A nested loop over the same collection does work proportional to the square of its size — which is why doubling the data quadruples the time. Chapter 12's search algorithms are the first place that difference matters.

41. Reusing the same loop variable in both loops

Trap

The trap

The inner loop reuses the outer loop's variable, and the outer loop never finishes properly.

for (int i = 1; i <= 3; i++) {
    for (i = 1; i <= 3; i++) {     // same variable!
        System.out.print(i);
    }
    System.out.println();
}
what happenswhy
the inner loop resets i to 1it shares the outer loop's variable
the inner loop runs i up to 4then exits
the outer update makes i 5the outer condition fails immediately
resultone row, not three

This compiles, because reusing an existing variable in an initializer is legal. It just does not do what a nested loop is supposed to do.

The fix

Each loop gets its own variable, declared in its own initializer.

for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 3; j++) {
        System.out.print(j);
    }
    System.out.println();
}
variablecontrolled byrange
ithe outer loop1 to 3
jthe inner loop1 to 3, restarted for each i

Because j is declared inside the outer loop's body, it is created fresh on every outer pass — which is exactly the behaviour you want. Conventional names for nested loop variables are i, j and k.

42. Where does the line break go?

Prediction

The println has moved inside the inner loop.

for (int x = 1; x <= 2; x++) {
    for (int y = 1; y <= 2; y++) {
        System.out.print(x * y);
        System.out.println();
    }
}
passprintedthen
x=1, y=11newline
x=1, y=22newline
x=2, y=12newline
x=2, y=24newline

Predict first

What shape is the output?

  • Four lines, one number each
  • Two rows of two numbers
  • One line with four numbers
  • Two lines, then two more

Correct: Four lines, one number each

Why: The println is inside the inner loop, so it runs after every single number rather than at the end of each row. To get a grid the println must be inside the outer loop and after the inner one — which is the one line that decides the whole shape of the output.

43. Step through a nested loop

Invariant

Watch both loop variables at once.

Step through it

How many times does the inner loop variable get reset to 1?

  1. Both start at 1. The first cell of the first row is printed.
  2. y advances; x has not moved. Still the first row.
  3. y reaches 3 and fails the inner condition. The newline runs, ending row one.
  4. The outer update makes x 2, and the inner loop starts over with a FRESH y of 1.
  5. y advances again within the second row.
  6. The inner loop ends and row two is closed.

Once per outer pass. That resetting is what makes the inner loop cover its whole range for every value of the outer variable — and it is why the two must be different variables.

44. What happens as the table grows?

Scale up

Watch the number of printf calls as the loop bounds increase.

Step through it

If the size doubles, by what factor does the work grow?

  1. A ten-times table. 100 cells, instant.
  2. Ten times bigger in each direction, and a hundred times more work.
  3. Ten times bigger again, and ten thousand times the original work. Now it is slow enough to notice.

By four. Nested loops over the same collection do work proportional to the square of its size, so doubling the data quadruples the time. This is the first appearance of an idea that Chapter 12 makes central when it compares sequential and binary search.

45. Characters, and which loop to use

Section

Sections 6.5-6.6

46. char stores a single character

Concept

Some of the most interesting problems in computer science involve searching and manipulating text. Strings provide a method named charAt, which returns a char — a data type storing an individual character, as opposed to strings of them.

String fruit = "banana";
char letter = fruit.charAt(0);     // 'b'

if (letter == 'A') {
    System.out.println("It's an A!");
}
literalquotesholds
'A'singleexactly one character
"A"doublea string that happens to be one character long
'\t'singleone character — an escape sequence is still one character
'AB'singleillegal — a char literal holds only one character

The argument 0 means the character at index 0. String indexes range from 0 to n-1, where n is the length of the string — so the first character is at 0, not 1.

47. The index ruler

Picture it

Every string method in the next lesson takes an index. Drawing the ruler once now saves a great deal of confusion later.

Figure (svg): The string banana with each character in a numbered box, indices 0 through 5, and the first character highlighted

Note where the numbering starts and where it stops. banana has length 6 and its last character is at index 5 — a fact that causes one specific exception in the next lesson.

48. Looping over the alphabet

Worked example

Characters work like the other data types you have seen. The increment operator works on them, which makes this loop possible.

System.out.print("Roman alphabet: ");
for (char c = 'A'; c <= 'Z'; c++) {
    System.out.print(c);
}
System.out.println();
partvaluenote
initializerchar c = 'A'the loop variable is a char
conditionc <= 'Z'characters compare with relational operators
updatec++moves to the next character
outputABCDEFGHIJKLMNOPQRSTUVWXYZ26 passes

Declare the loop variable as a char.

Why: The for loop does not require an int — any type that can be compared and updated will do.

Compare characters with <=.

Why: This works because each character has a numeric code point behind it.

Increment with c++.

Why: Which moves to the next code point, and therefore the next letter.

Note why the letters are consecutive.

Why: In Unicode the uppercase Roman letters occupy consecutive code points, so incrementing works. That is a property of the encoding, not a guarantee about all alphabets.

Verify: Expect the 26 uppercase letters with no spaces between them.

Why: Then try starting at 'a' and ending at 'z' for lowercase. If you tried 'A' to 'z' you would get the letters plus the six punctuation characters that sit between the two alphabets in Unicode — which is a good demonstration that the ordering is the encoding's, not the alphabet's.

49. What does this print?

Prediction

A char loop with a small range.

for (char c = 'a'; c <= 'e'; c++) {
    System.out.print(c);
}
cconditionprinted
'a' to 'e'trueabcde
'f''f' <= 'e' is falseloop ends

Predict first

What is the output?

  • abcde
  • abcd
  • a b c d e
  • ABCDE

Correct: abcde

Why: The loop runs from 'a' through 'e' inclusive because the condition uses <=, and print adds nothing between the characters. Lowercase letters occupy consecutive Unicode code points, which is what makes incrementing a char step through the alphabet.

50. Unicode, and casting an int to a char

Concept

Java uses Unicode to represent characters, so strings can store text in other alphabets — Cyrillic, Greek — and non-alphabetic languages like Chinese. Each character is represented by a code point, which you can think of as an integer.

System.out.print("Greek alphabet: ");
for (int i = 913; i <= 937; i++) {
    System.out.print((char) i);
}
System.out.println();
code pointcharacter
65A
913the first uppercase Greek letter
937the last one
(char) 913converts the int to its character

Unicode — An international standard for representing characters in most of the world's languages.

The cast (char) i is Lesson 3b's type cast doing a new job: converting each integer in the range to the corresponding character. Casting works here because the types are compatible — a char really is a number underneath.

51. Choosing the wrong kind of loop

Trap

The trap

A for loop where the number of repetitions is unknown. It cannot express the job.

// how many times will the user type something invalid?
for (int i = 0; i < ???; i++) {
    // there is no sensible bound to write here
}
situationhow many repetitions?can a for header say it?
print the alphabet26 — known in advanceyes
validate user inputunknown — depends on the userno
iterate a string's charactersits length — knownyes

A for loop is definite: you know at the beginning how many times it will repeat. When you do not, the header has nothing to put in its condition slot except a flag, which defeats the purpose.

The fix

A while loop is indefinite — use it when the repetition count is not known in advance.

System.out.print("Enter a number: ");
while (!in.hasNextDouble()) {
    String word = in.next();
    System.err.println(word + " is not a number");
    System.out.print("Enter a number: ");
}
double number = in.nextDouble();
kindmeansuse for
for — definiteyou know how many repetitions at the startcounting, iterating a string, a fixed range
while — indefiniteyou do not know how manyvalidating input, reading until a sentinel, searching

Compare this with Lesson 5b's validation, which gave up after one bad input. This version keeps asking until the user types something usable — a genuine improvement, and only a while loop can express it. It is also easier to read the Scanner calls when they are not all on one line.

52. for or while?

Definition probe

Ask whether you know the number of repetitions before the loop starts.

Sort into buckets

Sort each task by the loop that fits.

for — definite
print the 26 letters of the alphabet; print a 10 by 10 multiplication table; count from 1 to n, where n was read from the keyboard
while — indefinite
keep asking until the user types a number; read lines from a file until it ends
f
The number of repetitions is known when the loop begins — even if, as in the last case, it was only discovered a moment earlier. A for header can state it.
w
The number of repetitions depends on something that happens during the loop, so there is no count to put in a for header.

53. char literal or String literal?

Discrimination

Single quotes hold one character; double quotes hold a string.

Sort into buckets

Sort each literal.

a char
'b'; '\t'
a String
"b"; "banana"; ""
ch
Single quotes, containing exactly one character. An escape sequence counts as one character, which is why '\t' is legal.
st
Double quotes. A string can hold any number of characters including none at all — the empty string is still a String.

54. Would 'A' to 'z' give both alphabets?

Counterexample

The letters are consecutive. Test how far that goes.

Discussion prompt

for (char c = 'A'; c <= 'Z'; c++) prints the uppercase alphabet. What would for (char c = 'A'; c <= 'z'; c++) print — and what does the answer tell you about what 'consecutive' really means here?

Hint: There are 26 uppercase and 26 lowercase letters. How many code points lie between 'A' and 'z'?

Answer:

It prints 58 characters: the 26 uppercase letters, then six punctuation characters, then the 26 lowercase letters. The two alphabets are consecutive within themselves but are not adjacent to each other.

So c++ on a char is not really 'next letter' — it is next code point, and the letters happen to be laid out conveniently. That distinction matters as soon as you leave the Roman alphabet, and it is why the Greek example in this section loops over integers and casts rather than incrementing a char.

The general habit: when something works, ask whether it works because of the thing you are relying on or because of a coincidence of the representation.

55. while and for, side by side

Comparison

They have the same capabilities. Fill the blanks to see where each is clearer.

Comparison matrix

whilefor
initializationon the line before the loopthe first slot in the header
updateusually the last statement of the bodythe third slot in the header
loop variable scopewhatever block declared itlocal to the loop, if declared in the initializer
kind of repetitionindefinite — you do not know how manydefinite — you know how many

Any for loop can be rewritten as a while loop and vice versa, so the choice is entirely about which one makes the intent obvious to a reader.

56. The pattern to carry away

Pattern

Every loop has the same three moving parts, whichever form you write it in — and checking all three is how you know it terminates.

// the three parts, in a for loop
for (int i = 0; i < n; i++) {
    // body
}

// the same three parts, in a while loop
int i = 0;              // initialize
while (i < n) {         // condition
    // body
    i++;                // update
}
check before running any loopif it is missing
is the loop variable initialised?the loop may not compile, or starts from anything
does the condition mention it?the loop cannot depend on the variable's progress
does something update it?an infinite loop
does the update move TOWARD the exit?an infinite loop, in the other direction

57. Check: counting the passes

Check

Work it out before you click.

int count = 0;
for (int i = 3; i <= 9; i += 3) {
    count++;
}
iconditionbody runs?
3trueyes
6trueyes
9trueyes
12falseno

Check your understanding

What is count after the loop?

  • A. 3 (correct)
  • B. 4
  • C. 9
  • D. 7

Answer: A

Why: i takes the values 3, 6 and 9 — three passes — and then becomes 12, which fails the condition. The <= matters here: with < the loop would stop at 6 and count would be 2.

Why B tempts people
This counts a fourth pass at i = 12, but 12 is greater than 9 so the condition is false and the body does not run.
Why C tempts people
This is the last value of i used, not the number of times the body ran.
Why D tempts people
This counts every integer from 3 to 9, but the loop steps by 3 rather than by 1.

58. Check: nested loop count

Check

Work it out before you click.

int n = 0;
for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 4; j++) {
        n++;
    }
}
looppasses
outer5
inner, per outer pass4
total20

Check your understanding

What is n after both loops?

  • A. 20 (correct)
  • B. 9
  • C. 5
  • D. 4

Answer: A

Why: The inner loop runs 4 times for each of the outer loop's 5 passes, so the inner body runs 5 times 4, which is 20. Nested loops multiply — adding would be the answer for two loops written one after the other rather than one inside the other.

Why B tempts people
This adds 5 and 4, which would be right for two consecutive loops but not for a nested one.
Why C tempts people
This counts only the outer loop's passes and ignores that the inner body runs several times within each.
Why D tempts people
This counts only one pass of the inner loop.

59. Check: scope of the loop variable

Check

Work it out before you click.

for (int i = 0; i < 3; i++) {
    System.out.println(i);
}
System.out.println(i);
lineis i in scope?
inside the loop bodyyes
the line after the loopno

Check your understanding

What happens when you compile this?

  • A. A compile error on the last line — cannot find symbol (correct)
  • B. It prints 0, 1, 2, 3
  • C. It prints 0, 1, 2 and then 2
  • D. It prints 0, 1, 2 and then 0

Answer: A

Why: A variable declared in a for loop's initializer exists only inside that loop, so the final println refers to a name that is out of scope. Declaring int i; before the loop and writing for (i = 0; ...) would make the last line legal, and it would print 3.

Why B tempts people
Nothing compiles, so nothing is printed. And 3 would never be printed inside the loop, since the condition fails at 3.
Why C tempts people
This assumes i keeps its last used value and remains accessible, but it is not accessible at all.
Why D tempts people
This assumes i resets, but the problem is scope rather than value.

60. The loop that nobody can prove terminates

Real world

Section 6.1 slips in a genuinely open mathematical problem, and it is worth taking seriously.

Discussion prompt

The Collatz loop halves n when it is even and computes 3n+1 when it is odd, stopping at 1. It has been checked for enormous starting values and always stops. Why is that not a proof — and what does the situation tell you about reasoning about loops in general?

Hint: How many starting values are there?

Answer:

Because there are infinitely many starting values, and checking any finite number of them says nothing about the rest. This is the Collatz conjecture, and nobody has proved or disproved it.

The general lesson is the one Think Java draws: in general it is not easy to tell whether a loop terminates. For the countdown you can prove it — n decreases by one each pass and the condition tests against a fixed bound. For Collatz you cannot, because n sometimes increases.

What to do about it in practice: prefer loops whose variable moves monotonically toward the exit condition, because those you can check at a glance. When a loop's variable moves both ways, you are in territory where testing is not proof — and that is worth knowing before you rely on it.

61. How sure are you?

Commit first

Commit to an answer and to your confidence.

Predict first

How many times does the body of for (int i = 1; i <= 5; i++) run?

  • 5
  • 4
  • 6
  • It depends on the body

Correct: 5

Why: i takes the values 1, 2, 3, 4 and 5, and the body runs for each of them; on the sixth test i is 6 and the condition fails. Note the contrast with for (int i = 0; i < 5; i++), which also runs five times but with i taking 0 through 4 — both are five passes, and which one you want depends on whether you are counting or indexing. Getting these two straight now matters enormously in the next lesson, where the index of the last character is length minus one.

62. Explain it to someone else

Explain it

Two minutes, out loud, with a table.

Discussion prompt

A classmate's loop prints one fewer number than they expect. Teach them how to trace a loop on paper — what the columns should be, and what to write in each row. Then explain why a loop variable ends up one step past the last value used.

Hint: The table needs a column for the value at the TOP of each pass.

Answer:

Make a table with one row per pass. The columns are: the value at the top of the pass, whether the condition holds, what the body does, and the value at the end of the pass. The last row is the one where the condition fails and the body does not run.

And the variable ends past the end because the update runs after every body, including the last one. So the final update pushes it to the value that fails the condition — that failing value is what stops the loop.

If the table has no row where the condition is false, it is incomplete. That row is the one that explains both the number of passes and the final value.

63. Exit ticket

Exit ticket

One question before you close the deck.

Predict first

When should you choose a while loop over a for loop?

  • When you do not know in advance how many times the loop will repeat
  • When the loop body is longer than one statement
  • When you need to count downwards
  • When the loop variable is a char

Correct: When you do not know in advance how many times the loop will repeat

Why: A for loop is definite — you know at the beginning how many repetitions there will be, and the header can state it. A while loop is indefinite, which is what you need for validating input, reading until a file ends, or searching until something is found. The two forms have identical capabilities, so the choice is entirely about which one makes the intent visible: counting downwards, a long body and a char loop variable are all perfectly comfortable in a for loop.

64. Draw the whole lesson

Connect it up

One page, from memory.

Draw it

Draw a flowchart for a while loop, marking the point where the condition is tested and the arrow that loops back. Beside it, write the same loop as a for loop and label its three parts. Then make a four-column trace table for for (int i = 1; i <= 4; i++) including the final row where the condition fails, and write down the value of i on that row. Finally, write the three questions you would ask to check that a loop terminates.

65. Recap

Recap

Six sections that add the last of the five basic instructions, and the tools for writing it so that it stops.

if you remember one thingit is this
about terminationfind the statement that changes the condition's variable
about countingfor (int i = 0; i < n; i++) runs exactly n times
about choosingdo you know how many? for. Not sure? while.

Sources

  1. Downey & Mayfield, Think Java, 2nd edition (Green Tea Press / O'Reilly, 2020) — Think Java 2e, Chapter 6 (Loops and Strings), Sections 6.1-6.6, pp. 89-98
  2. The Java Tutorials — The for Statement
  3. Think Java 2e — free online edition and source code

Want this taught 1-on-1? Alexander tutors Java — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108