Iteration is very important in programming: a lot of
programming tasks involve repetition. For example,
you might want to take a list of users and send each
one an email with promotions. Or you might want to
have code that goes through a list of orders and
sum the order totals.
Iteration is performed using loop structures.
There are different kinds of these loop structures:
some count from a starting value to an ending
value, and some will execute indefinitely until
a certain condition is met. Other loops will execute
for each object or item in a list. It's not only
important to learn how to write efficient loops, but
also how to choose the right loop for the right job.
There are two kinds of while loops, but this section talks
about the standard While Loop, which is also referred to as the
top-checking while loop or
pre-test while loop. You'll understand why
we use these terms in a moment.
In a while-loop, the loop-continuation-condition
is a valid relational/logical expression that evaluates to
true or false.
As long as this expression evaluates to true,
the loop's body will execute.
When the loop condition becomes
false, the loop will terminate, and control will
move to any statements that appear after the loop. For
example, the loop below iterates 4 times and then prints
"Done!":
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!".
The standard while loop is a pre-test loop, or
top-checking loop. This means that the test
or boolean expression that determines 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.
Let's do another example: what do you think is the output
of this loop? Try and figure it out before you run it.
public class LoopThis {
public static void main(String[] args) {
int number = 4
int counter = 1;
while (counter <= number) {
System.out.print(counter + " ");
counter++;
}
System.out.println("\nDone!");
}
}
In this code, the program first declares number
and initializes it to the value 4.
Next, a counter variable is declared and 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 value 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 1 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).
For the first
iteration of the loop, the counter
variable has a value of 1. Then the
loop condition is evaluated (is counter <= number?).
Because 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 during the loop's execution,
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
int number = 4;
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.
Note that if you have more than one statement in the body
of your loop, you will need to enclose the statements in braces.
But if your loop has exactly one statement inside the loop body,
you can leave off the braces:
while (count <= 5)
System.out.println(count++);
System.out.println("This statement is after the loop.");
Just make sure you pay attention to the logic of your loops
if you leave off the braces. When you start
nesting
loops and other structures, this can cause problems if you're
not careful.
Another thing to be careful of is how you write your
loop expression. For example, what does this loop output?
public class NeverExecutes {
public static void main(String[] args) {
int x = 5;
while (x < 5) {
System.out.println(x);
x--;
}
}
}
Because x starts with a value of 5, the
while-loop's condition is false as soon
as the loop begins. This means the code block is never entered,
it never executes.
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
1. Examine each of the loop headers below, particularly
the loop condition. Under what conditions does the
loop terminate? For example, if the loop was
while (foo == 5), the loop would terminate
when foo became equal to a value that is not 5.
while (recCount != 10)
while (userInput.equals(""))
while (x >= 5)
while (x < 5)
while ( (x < 5) && (y > 10) )
2. Go back to the example that printed from 1 to 4:
public class LoopThis {
public static void main(String[] args) {
int number = 4
int counter = 1;
while (counter <= number) {
System.out.print(counter + " ");
counter++;
}
System.out.println("\nDone!");
}
}
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);
1. Examine each of the loop headers below, particularly
the loop condition. Under what conditions does the
loop terminate?
while (recCount != 10) when recCount contains the value 10)
while (userInput.equals("")) when the userInput String object
contains characters (when it isn't empty)
while (x >= 5) when x's value becomes less
than 5
while (x < 5) when x's value becomes 5 or more
while ( (x < 5) && (y > 10) ) when x's value becomes 5 or more
OR when y's value becomes 10 or less
2. How would you modify the sample program so that the output appears
instead as:
1
2
3
4
Done!
Solution: Change the print() inside the loop to a println().
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);
Solution:
15
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;
}
}
}
Solution: You have an endless loop because counter
will never be equal to 10.
5. a. Write a loop that prints the numbers from 1 to 10 with
their squares.
Solution:
public class Question5a {
public static void main(String[] args) {
int counter = 1; // init counter
// while counter is 10 or less
while (counter <= 10) {
// print counter and its square
System.out.printf("%d %10d%n", counter, Math.pow(counter));
counter++; // next counter
}
}
}
5. b. How would you make the loop do the same output
backwards (from 10 to 1)?
Initialize the counter to 10
Change the loop condition to counter >= 1
Change the increment to a decrement (counter--)
public class Question5b {
public static void main(String[] args) {
int counter = 10; // init counter
// while counter 1 or more
while (counter >= 1) {
// print counter and its square
System.out.printf("%d %10d%n", counter, Math.pow(counter));
counter--; // next counter
}
}
}
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
public class Question6 {
public static void main(String[] args) {
int counter = 2;
while (counter <= 20) {
System.out.printf("%d ", counter);
counter += 2;
}
}
}
This will work, too:
public class Question6 {
public static void main(String[] args) {
int counter = 0;
while (counter < 20) {
counter += 2;
System.out.printf("%d ", counter);
}
}
}
7. What is the output of each of the following loops?
Example 1:
4
3
2
1
Example 2:
1
2
3
4
Example 3:
(no output)
Example 4:
3
2
1
0
Example 5:
9
8
7
6
5
Example 6:
1, 2
2, 1
3, 0
4, -1
x: 5 y:-1
Do-While Loops
A do-loop or do-while loop is often referred to as a
post-test loop or bottom-checking loop because the
condition that checks for loop continuation is at the bottom of the loop,
instead of the top. Here's the general syntax of a do-while loop:
do {
// statement 1
// statement 2
// etc...
} while (loop-continuation-condition);
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.
Let's work through a do-while loop so we can understand
how it works:
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 earlier in the
lesson 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.
While-Loop vs Do-While-Loop
The key difference between a while-loop and a do-while
loop 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, because 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 (or post-test) do-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
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.
1. What's the output of each of the following code segments:
Example 1:
4
3
2
1
Example 2:
9
8
7
6
5
4
Example 3:
1
Question 2a:
Question 2b:
Question 2c:
Priming Read / Continuing Read
The priming read / continuing read is a common pattern you see
in programs that use loops. It is often used to validate
user inputs (although that's not the only time it's used), 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.
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!
Redundant code: we have the validation expression
number < 1 || number > 100 twice.
Inefficient: every time the loop executes, we evaluate
the if-statement (which involves 3 different operators,
all of which require processing).
Nested Structures: Although useful, if you don't need
them, don't use them. They decrease the readability
and efficiency of your program. (we will learn more about
nested
loops/ifs in a later lesson).
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
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.
Test data and sample output:
Enter final grade #1 (negative number quits): 78.5
Enter final grade #2 (negative number quits): 79
Enter final grade #3 (negative number quits): 85.1
Enter final grade #4 (negative number quits): -5
Average Grade: 80.87
Enter final grade #1 (negative number quits): -1
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
double total = 0.0, average = 0.0;
int numCourse = 0;
System.out.printf("Enter final grade #%d (negative number quits): ",
numCourse + 1);
double grade = in.nextDouble();
while (grade >= 0) {
numCourse++;
total += grade;
System.out.printf("Enter final grade #%d (negative number quits): ",
numCourse + 1);
grade = in.nextDouble();
}
if (numCourse > 0) { // avoid divide by 0
average = total / (numCourse);
System.out.printf("Average Grade: %.2f\n", average);
}
}
}
Exercises
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:
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.