Chapter 5. Repetition
One of the great virtues of computers is that they will repeat
mindless tasks without complaint. To facilitate such repetition, Java
includes statements types called loops, which allow a
program to specify some sequence of instructions that should be
repeated.
5.1. The while
loop
Java has a few categories of loops, and the most fundamental of
these is the while
loop.
The while
loop enables you to specify that some sequence of
statements should be repeated as long as some condition
is true (i.e., while the condition holds) . The template
for a while
loop looks like the following.
while(<thisIsTrue>) {
<statementsToRepeat>
}
You include the word while
, with a true/false expression in
parentheses (the parentheses are required), followed by a set of
braces including the lines you want to repeat. The parenthesized
expression is called the condition of the loop. The part
between the braces is the loop's body.
When the computer reaches a while
loop, it tests the condition
inside the parentheses to determine whether it is true. If so,
it executes the body (between the braces) and then checks the
condition again. It repeatedly checks the condition and executes the
body, until finally it finishes the body and the condition turns out to
be false. Each execution of the loop's body is called an
iteration.
Once the condition turns out to be false, the computer continues
to the first statement following the body (after the closing brace). (If
the condition never held in the first place, the computer skips past
the body immediately, with no iterations.)
Figure 5.1 illustrates this process.
Figure 5.1: A flowchart for the while
statement.
To see an example of a while
loop, let's look back to our
DrawSquare
program (Figure 4.1).
That program was a bit repetitive: We repeated the same two lines four
times, once for each side.
We could replace lines 10
to 16 with a while
loop, with each
iteration of the loop drawing a single side of the square.
Figure 5.2 contains such a program.
Figure 5.2: The DrawSquareLoop
program.
1 import turtles.*;
2
3 public class DrawSquareLoop extends TurtleProgram {
4 public void run() {
5 double sideLength;
6 sideLength = this.readDouble();
7
8 Turtle boxTurtle;
9 boxTurtle = new Turtle(100 - sideLength / 2, 100 - sideLength / 2);
10 int drawn; // counts how many sides are complete
11 drawn = 0; // so far none are complete
12 while(drawn < 4) {
13 boxTurtle.forward(sideLength);
14 drawn = drawn + 1; // we've completed one more side
15 boxTurtle.right(90);
16 }
17 boxTurtle.hide();
18 }
19 }
The computer would execute the DrawSquareLoop
program as
follows.
Lines
5–9:
These lines are the same as before: They determine the size of
the square and initialize the turtle.
Lines
10–11:
The computer creates a variable drawn
to count how
many sides of the square boxTurtle
has drawn.
Because boxTurtle
hasn't drawn any sides yet,
the program initializes drawn
to 0.
Line 12: The computer
checks whether the condition drawn < 4
holds. It is, so the
computer proceeds to execute each of the statements in the
braces.
Line 13: The computer tells boxTurtle
to move forward
sideLength
pixels.
Line 14: The computer now reassigns
drawn
to a new
value: In particular, it is assigned to the value of drawn + 1
.
Since drawn
is currently assigned to the value 0, the value of
drawn + 1
is 1, and so 1 is the value now assigned to the
drawn
name.
Notice the peculiarity of this line. If this were an algebra class,
you'd look at this as an equation, cancel drawn
from both sides,
and end up with 0 = 1. But in Java, the equal sign represents
assignment, not equality as in algebra. So the
computer doesn't think about the relationship between the two
sides: It simply evaluates the right-hand side first, and then it
assigns the left-hand variable to reference whatever result falls
out.
Line 15: The computer tells
boxTurtle
to turn 90° clockwise,
so that boxTurtle
now faces south.
Line 16: Having reached the end of the while
loop, the
computer proceeds to the top of the loop again to check the condition
again, in line 12.
Lines
12–16: The computer checks whether the condition
drawn < 4
still holds. Since drawn
is 1, it
is does. Hence we proceed:
The computer tells boxTurtle
to move forward,
reassigns 2 to drawn
, and tells boxTurtle
to turn facing
west.
Lines
12–16: The
condition drawn < 4
still holds.
The computer tells boxTurtle
to move forward,
reassigns 3 to drawn
, and tells boxTurtle
to turn facing
north.
Lines
12–16: The
condition drawn < 4
still holds.
The computer tells boxTurtle
to move forward,
reassigns 4 to drawn
, and tells boxTurtle
to turn facing
east.
Line 12: The condition drawn < 4
is finally false. So
the computer is done with the while
loop and now proceeds to
the first statement following the loop's body,
line 17.
Line 17: The computer tells
boxTurtle
to hide itself.
One subtlety of while
loops is that the computer checks
the condition only when it reaches the end of the loop's
body. In the last iteration of the while
loop of this example,
after drawn
is assigned the value
4 in line 14, the turtle
nonetheless turns to
face east in line 15,
because the computer must complete the body of the while
loop
before checking the condition again.
Notice that a while
loop involves no semicolons!
Beginners are often tempted to add one anyway, after the
parentheses.
while(drawn < 4); { // Wrong! The semicolon messes up this code.
drawn = drawn + 1;
}
Irritatingly, the Java compiler will accept this with a very
different meaning than intended: It will
understand the body of the loop to be an empty statement terminated
by the semicolon before the opening brace, and the part
in braces will be something to be done only once the loop completes.
But the loop will never complete, because the computer
will end up repeatedly checking whether drawn < 4
and then
doing nothing.
5.2. Conditions
Alongside int
and double
among the primitive types is the
boolean
type, which is used to represent whether some fact holds.
There are only two valid boolean
values:
true
and false
. (And if you ever want to refer to these
constant boolean
values in a program, that's exactly how you
write them: true
or false
.)
Why call this type boolean? It's named after a
19th-century mathematician named George Boole. Boole was the first to
notice that and and or, two common ways to combine
true/false values, had some marked similarity to multiplication and
addition of integers. This observation led to a sort of arithmetic of
true/false values that came to be called Boolean algebra.
When Boole noticed this, people scoffed at Boole's work as being a
rather pointless game. But it turned out to form the foundation of
designing digital circuits.
The most common usage of the boolean
type is implicit:
When you compare two numerical values (as done using the `<
'
operator on line 12 of Figure 5.2), the comparison
operator takes two numeric values and computes a boolean
value.
Java has several comparison operators, all of which operate on
two numerical values and result in a boolean
value.
< | less than |
<= | less than or equal |
> | greater than |
>= | greater than or equal |
== | equal |
!= | not equal |
When the computer reaches a while
loop as on
line 12 of Figure 5.2,
it evaluates the expression in the parentheses. Because the expression
must compute a boolean
value, the result will be either
true
or false
, and the computer will use this result
to determine whether to go through the body of the loop.
Notice the doubled equal sign (==
) for testing equality!
In Java, the single equal sign (=
) represents assignment,
as we've seen in our assignment statements. Beginners often find this
somewhat confusing, but eventually the distinction is easy:
Use ==
when you want to see whether
two existing values are equal (without changing anything), and
=
when you want to change the value of a variable.
You'll almost never see a single equal sign inside a while
loop.
One occassional pitfall when comparing double
s is that round-off
errors can cause unexpected results. For example, 1.2 - 1.1
turns out to be 0.09999999999999985
, which is different from
0.1
. So if we evaluated 1.2 - 1.1 == 0.1
, the value
would unexpectedly
turn out to be false
. To avoid errors, when you are testing to
see if two double
s are equal, you should instead test to see if
the absolute value of their difference is small.
Sometimes you will want to combine conditions together to create a more
complex condition.
Java incorporates other operators to permit this.
&& |
and |
(true if both sides hold) |
|| |
or |
(true if either side holds, or if both hold) |
! |
not |
(true if expression doesn't hold) |
For example, to see whether n
refers to a value between 1 and 10,
we would want to see if n
is at least 1 and at most 10. We can do
this using the &&
operator: n >= 1 && n <= 10
.
(Java would not allow 1 <= n <= 10
.
)
Here are some other examples.
!(n >= 1 && n <= 10) |
true if n is not between 1 and 10 |
n < 1 || n > 10 |
true if n is less than 1 or greater than 10 |
In fact, these operators fall into the same precedence hierarchy as
all the other types we have seen so far. Here's all of the operators we
have seen so far listed in order of precedence. (Technically, the
assignment symbol is also an operator, which would appear at the very
bottom level below, but it's better not to think of it as an
operator.)
! -
(unary operators)
* / %
+ -
< <= > >=
== !=
&&
||
The highest level is reserved for
unary operators, which are operators
that operate on only a single value, including the not
operator !
and the negation operator -
. The minus sign can
be used both as a unary operator (in which case it represents negation,
as in abs = -x;
) and as a binary operator (in which case
it represents subtraction, as
in diff = y - x;
).
5.3. Incrementing assignments
You'll find that, in the context of loops, it's quite frequent that
you write a statement like line 14 of
DrawSquareLoop
.
drawn = drawn + 1;
This reassigns drawn
to one more than it was before.
This operation is so common that Java has a way of abbreviating it,
to save you the bother of having to type the variable name twice.
drawn++;
Similarly, Java also has an abbreviation for decrementing:
i--;
is equivalent to i = i - 1;
.
Beginners sometimes have difficulty distinguishing between
drawn++
and drawn + 1
. These two fragments
are not at all synonymous. The first — drawn++
— changes the value of the variable drawn
.
By contrast, drawn + 1
does not have any effect on
drawn
: It computes the number that is one more than drawn
,
but drawn
does not change.
For those cases when you want to add something other than 1 to a
variable, Java has another shortcut, the +=
operator.
drawn += 10;
This line would be equivalent to drawn = drawn + 10;
.
You can analogously use -=
, *=
, /=
, and %=
.
Exercise 5.1
For each of the following conditions,
describe the variable values for which the condition is true.
a. | x * x == x && x > -1 |
b. | score > 90 || (bonus && score == 89) |
c. | !(k == 1) |
Exercise 5.2
Write a condition to test whether an int
variable year
represents a leap year. (Remember that a year is a leap year if it is a
multiple of 4, except for years that are multiples of 100 but not
400. For example, 1992 and 2000 are leap years; 2100 is not.)
Exercise 5.3
Without running the program on a computer, draw a picture of what the
WhileMystery
program of Figure 5.3 would
draw on the screen.
Figure 5.3: The WhileMystery
class.
1 import turtles.*;
2
3 public class WhileMystery extends TurtleProgram {
4 public void run() {
5 Turtle crush = new Turtle(100, 100);
6 int len = 10;
7 while(len < 200) {
8 crush.forward(len);
9 crush.left(90);
10 crush.forward(len);
11 crush.left(90);
12 len += 10;
13 }
14 crush.hide();
15 }
16 }
Exercise 5.4
Modify the DrawSquareLoop
program of
Figure 5.2 so
that it insists the user types a number between 5 and 195: As long
as the user types a number outside this range, the compiler should ask
again and again.
Exercise 5.5
Modify the DrawSquareLoop
program of
Figure 5.2 so
that it draws an octagon in the center of the window. It should read a
single number from the user, configuring the length of each side of the
octagon to be drawn.
If s represents each side's length, then
the left vertex of the centered octagon's top horizontal edge
would be at
(100 − 0.5 s, 100 − 1.207 s).