Iteration

Things To Do First

Things To Do Later

The While Loop

Chapter 5.1 explains why loops are important to programming. Make sure you read this section and understand it, as it is the foundation of what you will be learning in the next few classes.

Chapter 5.2 introduces you to the while loop. This is a pre-test loop, or top-checking loop. This means that the test to determine whether or not the loop should continue is at the top of the loop. Alternatively, the test condition can go at the bottom of the loop, as we'll see later. The general format of a while loop can be found at the start of Chapter 5.2. Note that if you have more than one statement in the body of your loop, you will need to enclose the statements in braces:

while (loop-continuation-condition)
{
	// statement 1
	// statement 2
	// etc...
}

In a while-loop, the loop-continuation-condition is a valid condition that evaluates to true or false. As long as this condition evaluates to true, the loop's body will execute. When the loop condition becomes false, the loop will terminate, and program flow to move to any statements that appear after the loop. For example, the loop below iterates 4 times:

public class BasicLoop {

    public static void main(String[] args) {

        int count = 1;
        while (count <= 4) {
            System.out.println(count + ":  Hello!");
            count++;
        }
        System.out.println(count + ":  Done!")
    }
}

The output of this loop would be:

1: Hello!
2: Hello!
3: Hello!
4: Hello!
5: Done!

Note that the loop iterates 4 times for the values 1, 2, 3, and 4 of the count variable. Inside the last iteration, the variable gets incremented to 5. At this point, the loop condition (count <= 4) evaluates to false and the loop terminates. Then the last print statement executes; it prints the value of count followed by ": Done!".

See Figure 5.1 in Chapter 5.2 and try the animation (click the (b) button) to see how the while loop works. Notice that the condition is tested at the top of the loop. This implies that a while loop's code block might never execute, as in this example:

public class NeverExecutes {

    public static void main(String[] args) {

        int x = 5;
        while (x < 5) { 
            System.out.println(x);
            x--;
        }
    }
}

Since x starts with a value of 5, the while loop's condition is false as soon as the loop begins, so the code block is never entered.

Keep in mind that the condition on a while loop specifies the conditions under which the loop continues. The loop continues as long as the condition remains true; in other words, the loop terminates when the condition is false.

Exercises

[solutions]

1. For what values do each of these loops terminate?

  1. while (recCount != 10)
  2. while (userInput.equals(""))
  3. while (x >= 5)
  4. while (x < 5)
  5. while ( (x < 5) && (y > 10) )

2. a. What do you think is the output of this loop if the user enters the value 4?

import java.util.Scanner;

public class LoopThis {

    public static void main(String[] args) {

        System.out.print("Enter a value to count to:");
        int number = keysIn.nextInt();
        int counter = 1;
        while (counter <= number) {
            System.out.print(counter + " ");
            counter++;
        }
        System.out.println("\nDone!");
    }
}

In this code, the program first retrieves the number to count up to from the user. Next, a counter variable is initialized to 1. We need this counter to do the actual counting. We can't use the number variable, because we need that to store the number we want to count up to.

Next, the while loop condition states that the loop should continue as long as the value of the counter remains less than or equal to the value of the number variable. As long as this condition stays true, the body of the loop will execute repeatedly.

The body of the loop contains two statements - one that prints the value of the counter, and one that adds one to the counter. We need to increment the counter variable, otherwise the counter will always stay at its initial value and never change! This would result in an endless loop (a loop that never terminates).

So what happens if the user a value of 4? For the first iteration of the loop, the counter variable has a value of 1. When the loop condition is evaluated (is counter <= number?). Since the counter is 1 and the value of number is 4, this statement is true. The flow of execution moves inside the loop. The print statement is executed (displaying the value of counter (1) on the screen followed by a space). Then the counter is incremented; after this statement is done, the counter has a value of 2.

Once the body of the loop is finished executing, the flow of execution goes back up to the loop condition. The condition is evaluated again: is counter <= number? This statement is true, since counter is 2 and number is 4. The body of the loop is executed again, causing the value of 2 to be printed on the screen, and the counter to be incremented to a new value of 3.

Eventually at some point, when the incrementing statement executes, the counter will be incremented to the value of 4. When control moves back up to the while-loop condition, the condition will evaluate to true (counter <= 4 is still true when counter has a value of 4). The body of the loop will execute one more time: The value of counter (4) will be printed and the counter will then be incremented to 5.

After the counter is incremented to 5, control moves back up to the while-loop condition. At this point, the condition counter <= 4 is false, since counter is 5, and the value 5 is not less than or equal to 4. The loop terminates and control moves to the print statement that appears after the loop. This statement prints the value "Done!" on the screen and the program is finished.

The trace chart below shows the rest of the variable values and the output of this code.

Statement
Executed
Value of
counter
Value of
number
counter <=
number?
Output
Shown
System.out.print("Enter a value to count to:");    
int number = keysIn.nextInt(); 4  
int counter = 1;1   
while (counter <= number) {  true 
System.out.print(counter + " ");   1
counter++;2   
while (counter <= number) {  true 
System.out.print(counter + " ");   1 2
counter++;3   
while (counter <= number) {  true 
System.out.print(counter + " ");   1 2 3
counter++;4   
while (counter <= number) {  true 
System.out.print(counter + " ");   1 2 3 4
counter++;5   
while (counter <= number) {  false 
System.out.println("\nDone!");   1 2 3 4
Done!

The key thing to note as you look at the results is that the counter variable does actually get incremented one last time before the loop condition is false. The counter gets incremented to 5 after the value 4 is printed (which is the highest value the user wanted to count to). The loop condition still has to be checked, however. Just because the counter has been assigned a value of 5 doesn't mean the program knows to end the loop! The loop condition must first be evaluated - this is how the computer knows when to end the loop. When the condition is determined to be false, then the flow of execution can move down to the statement after the loop.

2. b. How would you modify this program so that the output appears instead as:

1
2
3
4
Done!

3. What is the output of the following code segment?

int counter = 1;
int sum = 0;
while (counter <= 5)
     sum += counter++;
System.out.println(sum);

4. What's wrong with the following program?

public class LoopProblem {
    public static void main(String[] args) {
        
        // print from 1 to 10 by 2's
        int counter = 1;
        while (counter != 10) {
            System.out.println(counter);
            counter += 2;
        }
    }
}

5. a. Write a loop that prints the numbers from 1 to 10 with their squares, like this:

1		1
2		4
3		9
4		16
5		25
6		36
7		49
8		64
9		81
10		100

5. b. How would you make the loop do the same output backwards (from 10 to 1)?

6. Write a while loop that counts from 1 to 20 by 2's on one line:

2 4 6 8 10 12 14 16 18 20

7. What is the output of each of the following loops?

Example 1:
int count = 4;
while (count > 0)
{
  System.out.println(count);
  count--;
}
Example 2:
int count = 1;
while (count < 5)
{
  System.out.println(count);
  count++;
}
Example 3:
int count = 3;
while (count <= 1)
{
  System.out.println(count);
  count++;
}
Example 4:
int count = 3;
while (count >= 1)
{
  System.out.println(count);
  count--;
}
System.out.println(count);
Example 5:
int count = 9;
while (count <= 10 && count > 4)
{
  System.out.println(count);
  count--;
}
Example 6:
int x = 1, y = 3;
while (x < 5 || y > 0)
{
  System.out.println(x++ + 
	", " + --y);
}   
System.out.print("x: " + x);
System.out.println(" y:" + y);

Do-While Loops

Read!
Do-While loops are covered in chapter 5.6.

A do-loop is often referred to as a post-test loop or bottom-checking loopbecause the condition that checks for loop continuation is at the bottom of the loop, instead of the top.

do 
{
	// statement 1
	// statement 2
	// etc...
} while (loop-continuation-condition);

You can see the general form of a do-while loop at the top of Chapter 5.6. Note the syntax carefully - there is a semi-colon after the while condition. This is because the braces of a do-while loop enclose the loop body, but not the while clause in the loop. Since the while clause appears after the closing brace, it requires a line-terminator (semi-colon) so that Java knows where the end of the while statement is.

See Figure 5.2 in Chapter 5.6 and try the animation (click the (b) button) to see how the do-while loop works. How is this chart different from the while-loop flowchart in Figure 5.1/Chapter 5.2?

public class BasicLoop {

    public static void main(String[] args) {

        int count = 1;
        do {
            System.out.println(count + ":  Hello!");
            count++;
        } while (count <= 4);
        System.out.println(count + ":  Done!")
    }
}

The code above shows the BasicLoop example from before as a do-while loop instead of a while loop. Trace the code and then try it out, and you'll see it performs the exact same task as the earlier example.

The key difference is that a while loop, a top-checking or pre-test loop, checks the condition of the loop before executing the loop body. The do-while loop, a bottom-checking or post-test loop, checks the condition of the loop after executing the loop body.

What does this mean? It means that the body of a while loop might never execute, whereas the body of a do-while loop is always guaranteed to execute at least once. See the following examples:

Example A: a while loop

What is the output of the following program?

public class LoopProblem {
    public static void main(String[] args) {
        
        int counter = 1;
        while (counter > 1) {
            System.out.println(counter);
            counter--;
        }
    }
}

In the program above, we first initialize counter to 1. Then we begin the loop: check the condition counter >= 1. The condition is false, becuase counter is 1, and 1 is not >= 1, so the loop ends right away and no output is printed.

Example B: a do-while loop

What is the output of the following program?

public class LoopProblem {
    public static void main(String[] args) {
        
        int counter = 1;
        do {
            System.out.println(counter);
            counter--;
        } while (counter > 1);
    }
}

First, we encounter the do keyword, which indicates we are about to enter a bottom-checking while loop.

The body of the loop prints the current value of counter (1) and then decrements counter. The counter variable now has a value of 0. The body of the loop has finished executing and now we move to the while and check our condition.

counter >= 1 is false, because counter (0) is not >= 1. So the loop now terminates, and the output of this program was just "1".

We can clearly see that these loops are the same, except that one checks the condition at the top and one checks the condition at the bottom. In both loops, the condition counter >= 1 was false the first time it was checked however, because the while loop checks the condition before the loop body is executed, the body of the loop never executes. Because the do-while loop checks the same condition after the loop body is executed, the body of the loop executes once before it is determined that the condition is false.

This summarizes what we said about the difference between pre-test loops and post-test loops: The body of a pre-test loop might never execute if the condition is false right away, whereas the body of a post-test loop is always guaranteed to execute at least once.

Exercises

[solutions]

1. What's the output of each of the following code segments:

Example 1:
int count = 4;
do 
{
  System.out.println(count);
  count--;
} while (count > 0);
Example 2:
int count = 9;
do 
{
  System.out.println(count);
  count--;
} while (count <= 10 && count > 4);
System.out.println(count);
                            
Example 3:
int count = 1;
do 
{
  System.out.println(count);
  count--;
} while (count > 1);

2. a. Write a program that requests a final grade. Use a do-loop to request the grade continuously as long as the grade entered is invalid. A grade is invalid if it is less than 0 or greater than 100. After a valid grade is entered, display it on the screen.

2. b. Modify the above program so that the user can cancel by entering the value 999.

2. c. Modify the program in 1. a. so that the user has only 5 tries to enter the grade. After 5 tries, the program terminates.

Priming Read / Continuing Read

The priming read / continuing read is a common pattern you see in programs that use loops. It is used in special circumstances, for example, say you want to ask the user for a positive number between 1 and 100, and you want to keep on asking repeatedly until they follow your instructions and enter a valid number:

import java.util.Scanner;

public class PrimingRead {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);

        int number = 0;  // why do we have to declare this here?
        do {
            System.out.print("Enter a number between 1 and 100, inclusive: ");
            number = in.nextInt();
        } while (number < 1 || number > 100);

        System.out.printf("You entered %d\n", number);
    }
}

Try this program in your editor and run it. What happens when you type -3? What happens when you type 333? Then type 33. The program should run until you enter the valid value of 33:

Enter a number between 1 and 100, inclusive: -3
Enter a number between 1 and 100, inclusive: 333
Enter a number between 1 and 100, inclusive: 33
You entered 33

The program works as we have intended! However, it's not enough to write nice code that works and is efficient. Your program also has to be user-friendly!

What if your user doesn't understand your instructions, or what if they are one of those users that doesn't really read things well? When they run the program and enter invalid data, it actually looks like they are entering several numbers - it doesn't tell them that they're doing something wrong, and that the program is asking repeatedly so it can get a correct value. This is NOT good programming.

Important!
ALWAYS give the user good feedback!! If you have to inform the user of a mistake they made, you should:
  • Be polite. Even if the mistake they're making is dumb, don't treat them like an idiot. Maybe they got something in their eye, or maybe they're being distracted by a co-worker.
  • Tell the user in a concise and clear way what they did incorrectly. Use simple language that is not technical.
  • Tell the user how to fix the problem right away.
Examples of bad user feedback:
  • "Error! Invalid input." -- it's not telling the user what they did wrong nor how they should fix it.
  • "There is an error on your form." -- Really? What? Where??
  • "Please enter an Integer value." -- most users don't know what an "Integer" is, and this error also doesn't say what field/input is supposed to be an "Integer".
  • "Price should be a number, Duh!" -- yes, we feel like saying worse things, but we don't. These are your customers, clients, and people who pay for your work/software, so be polite and respectful, even when they're being stupid.
Examples of good user feedback:
  • Error: Please enter value between 1 and 10.
  • Please enter a valid postal code in the form A1B 2C3.
  • Circle radius must be a positive, numeric value.
Read!
More detailed information about good error messages: Instructional Design.org: Bad Error Messages
For entertainment purposes (does contain foul language): The 5 Worst Error Messages in History

To make the program more user friendly, we should give the user a good error message... something like "Error: You must enter a value between 1 and 10." There are a few ways to do this. Some people choose to put an if-statement inside the loop, but it's not the best solution:

import java.util.Scanner;

public class PrimingReadBad {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);

        int number = 0;  // why do we have to declare this here?
        do {
            System.out.print("Enter a number between 1 and 100, inclusive: ");
            number = in.nextInt();
            if (number < 1 || number > 100)
                System.out.println("Error: You must enter a value between 1 and 10.");
        } while (number < 1 || number > 100);

        System.out.printf("You entered %d\n", number);
    }
}

There are SO MANY THINGS WRONG with this program!

A better solution is to use the priming read / continuing read pattern. This pattern allows you to ask the user for their input first. Then you start a top-checking loop that performs the validation of the user input:

import java.util.Scanner;

public class PrimingReadGood {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);

        // this is the "priming read" - it primes the number variable
        // by reading the user's first try at inputting a value
        System.out.print("Enter a number between 1 and 100, inclusive: ");
        int number = in.nextInt(); 

        while (number < 1 || number > 100) {
              System.out.println("Error: You must enter a value between 1 and 10.");

              // this is the "continuing read" - it asks the user for the input
              // again, allowing the loop to continue executing when needed
              System.out.print("Enter a number between 1 and 100, inclusive: ");
              number = in.nextInt();
        }

        System.out.printf("You entered %d\n", number);
    }
}

What this code does is it "primes" the number variable with the user's first try at inputting a value. Then it uses a top-checking loop to see if that number is valid or not. If the condition is true, the user's input is invalid, so it gives the user the error message and prompts them for a new number. The read inside the loop is the "continuing read" - it's what allows the loop to continue executing normally, by allowing the user to change the value of the number variable. As long as the user keeps entering invalid values, the loop will continue to execute:

Enter a number between 1 and 100, inclusive: -3
Error: You must enter a value between 1 and 10.
Enter a number between 1 and 100, inclusive: 333
Error: You must enter a value between 1 and 10.
Enter a number between 1 and 100, inclusive: 33
You entered 33

This version of the program is much more efficient and much clearer. And it does exactly what we want!

Exercise

(These are new questions.. I haven't gotten around to adding them solution to the Solutions page, yet. If you have done this program and want the solution, remind me in an email and I will add it.)

1. Use the priming read / continuing read pattern in a program that calculates the user's average grade for the semester: The user enters their final grades for each of their courses, and the program adds them to a total. After the loop terminates, the average grade is calculated and displayed.

Students can take any number of courses, so we don't know how many courses to ask for. To deal with this, we will tell the user to enter a negative grade (anything less than 0) when they're finished entering grades for their courses. This works, since we don't assign negative grades, anyway. Your program's loop should execute only as long as the user-entered final grade is not a negative value.

Exercises

[solutions]

1. For this program, use either a while-loop or a do-loop, whichever you think is most efficient. Write a program that records scientific test results (they'll have decimal values) from the user. As each test result is entered, add it to a total. After all the test results have been entered, display the total.

You don't know how many test results they'll enter, so after each result is entered, prompt the user with a question such as "Would you like to enter another test result? (Y/N)". The user can answer "Yes" or "No" too this question, or even just "Y" or "N". To capture this, we would use the Scanner's next() method to grab only the first word of the user input:

String answer = in.next();

However, we can make this program more efficient if we use a character value instead of a string, and just compare the first letter of the user's input (Y or N). There is a method in the String class called charAt(index). You give charAt() a string index (the position number, where the first character is position 0, the second position 1, etc) of the character you'd like to have and it will return that character at the specified index as a char value. For example:

"hello".charAt(0) // returns 'h'
"hello".charAt(1) // returns 'e'
"hello".charAt(2) // returns 'l'
"hello".charAt(4) // returns 'o'
"hello".charAt(5) // would give an error because there is no index 5

So since we only what the first character that the user types, we can use:

char keepGoing = 'Y';  // initialize to yes
...  // code code code
keepGoing = in.next().charAt(0);

Next, we want to see if the user says 'Y' to our prompt, meaning they'd like to enter another test result. So our loop condition could be something like keepGoing == 'y' || keepGoing == 'Y' because we don't know if the user will type an upper-case or a lower-case answer. If you prefer, you can use one of the String class's methods toUpperCase() or toLowerCase() to convert the user's answer to upper- or lower-case, and then compare. For example, I will use upper-case comparisons:

keepGoing = in.next().toUpperCase().charAt(0);

Then my loop condition would be keepGoing == 'Y'.

Add this functionality to your program, so your user can enter as many test results as they'd like.

2. Write a program that plays a simple dice game: repeatedly roll dice (generate 2 random numbers between 1 and 6) as long as the user wishes to play. For each roll, display "You Win!" if "doubles" are rolled (both dice show the same value), and display "You lose!" if the two dice rolls are different. Regardless of the result, display the rolls of the dice. After each roll, ask the user if they'd like to continue playing (Y/N). If they wish to continue, roll again. If they want to quit, stop rolling. After the user quits, display the total number of rolls, the total number of winning rolls, and the percentage of wins e.g. 20 rolls with 5 wins would be 25%.