Using loops: The while loop
5.5 Using loops: The while loop
Programming languages offer you a specific construct to do a similar task repeatedly: a loop.
Concept:
A loop is a programming language construct that allows us to express commands such as “Do
A loop is a state- ment in program-
this statement 20 times” or “Call these two methods 3 million times” easily and concisely (with-
ming languages
out writing 3 million lines of code). Java has several different kinds of loop. The one we shall
that can execute a
investigate now is called a while loop.
section of code multiple times.
A while loop has the following form:
while ( condition ) {
statement ; statement ; ...
The Java keyword while is followed by a condition in parentheses and a block (a pair of curly brackets) containing one or more statements. These statements will be executed over and over, as long is the condition is true .
A very common pattern is a loop that executes some statements a given number of times. To do this, we use a loop variable as a counter. It is common practice to name a loop variable i , so we shall do this as well. Here is an example that executes the body of the while loop 100 times:
int
i = 0; while (i < 100) {
statement ; statement ; ...
Concept:
i = i + 1;
} A local variable is
a variable that is
There are several things worth noting in this code. First, it uses a concept that we have not
declared inside a method body. It is
encountered before: a local variable.
used for temporary
A local variable is a variable similar to a field. We can use it to store values in it, such as an inte-
storage.
ger number, or object references. It differs from fields in several respects:
A local variable is declared inside a method body, not at the beginning of the class;
It has no visibility modifier (private or public) in front of it; and
It exists only until the current method finishes running, then it will be erased. 1
1 Strictly speaking, this is not exactly correct. Local variables can also be declared inside other blocks, such as inside if statements or the body of a loop. They exist only until execution exits the block they
were declared in. The statement above is, however, correct if the local variable was declared at the begin- ning of a method.
70 | Chapter 5 ■ Making music: An on-screen piano
A local variable is declared by just writing the type of a variable, followed by its name: int i; After declaring the variable, we can assign a value. Here are these two statements together:
int i; i = 0;
Java allows a shortcut to write these two statements in one line, declaring the variable and assigning a value:
int
i = 0;
This line has exactly the same effect as the two-line version. This is the variant we have used in the code pattern for the while loop above.
Look at the pattern for the loop again—we should now be able to roughly understand what it does. We use a variable i and initialize it to 0. Then we repeatedly execute the body of the while loop, counting up i every time we do so. We continue this as long as i is less than 100. When we reach 100, we stop the loop. Execution will then continue with the code following the loop body.
There are two further details worth pointing out:
We use the statement i = i + 1; at the end of the loop body to increment our loop variable by 1 every time we have executed the loop. This is important. It is a common error to forget to increment the loop counter. The variable would then never change, the condition would always remain true, and the loop would continue looping forever. This is called an infinite loop, and is the cause of many errors in programs.
Our condition says that we execute the loop while i is less than ( < ) 100, not less than or equal ( <= ). So the loop will not be executed when i is equal to 100. At first glance, one might think that this means that the loop executes only 99 times, not 100 times. But this is not so. Because we started counting at 0, not at 1, we do execute 100 times (counting from 0 to 99). It is very common to start counting from 0 in computer programs—we will see some advantages of doing so soon.
Now that we know about a while loop, we can use this construct to create all our piano keys. Our piano will have 12 white keys. We can now create 12 keys by placing our statement to create
a key inside the body of a loop that executes 12 times:
int
i = 0; while (i < 12) {
addObject ( new Key ( “g” , “3a.wav” ), 300, 140);
i = i + 1;
Exercise 5.15 Replace the code in your own makeKeys method with the loop shown here. Try it out. What do you observe?
5.5 Using loops: The while loop
Trying out this code, it first looks as if only one key was created. This is deceptive, however. We do indeed get 12 keys, but since they have all been inserted at exactly the same coordinates, they are all lying right on top of each other, and we cannot see them very well. Try moving the keys in the piano world with your mouse pointer and you will see that they are all there.
Exercise 5.16 How can you change your code so that the keys do not all appear at exactly the same place? Can you change your code so that they get placed exactly next to each other?
The reason the keys all appeared on top of each other is that we inserted them all at the fixed location 300,140 into the world. We now want to insert every key at a different location. This is now actually quite easy to do: We can make use of our loop variable i to achieve this.
Exercise 5.17 How many times does our loop body execute? What are the values of i during each of the executions?
We can now replace the fixed x-coordinate 300 with an expression that includes the variable i :
addObject ( new Key ( “g” , “3a.wav” ), i*63, 140);
(The asterisk “*” is the operator for multiplication. Appendix D lists other operators that you can use with integer numbers.)
We have chosen i*63 , because we know that the image of each key is 63 pixels wide. The values for i , as the loop executes, are 0, 1, 2, 3, and so on. So the keys will be placed at x-coordinates 0,
63, 126, 189, and so on. When we try this we notice that the left-most key is not placed very well. Since object placement in
Greenfoot refers to the center point of an object, the center of the first key is placed at x-coordinate 0, which places the key half out of the screen. To fix this, we just add a fixed offset to each key coordi- nate. The offset is chosen so that the keys as a whole appear in the middle of our piano:
addObject ( new Key ( “g” , “3a.wav” ), i*63 + 54, 140);
The y-coordinate can remain constant, since we want all keys at the same height.
Exercise 5.18 Challenge exercise. (Do this exercise only if you are fairly confident about your programming. If you are just beginning, you may like to skip this exercise.)
Using fixed numbers in your code, such as the 140 or 63 in the statement above, is usually not the best solution, since it makes your code vulnerable to breaking when things change. For example, if we replace the key images with nicer images that have a different size, our code would not place them correctly.
72 Chapter 5 | ■ Making music: An on-screen piano
We can avoid using those numbers directly by calling the getWidth() and getHeight() methods of the key’s image. To do this, first assign the key object to a local variable of type Key when you create it, and then use key.getImage().getWidth() in place of the 63. Do a similar thing with the height.
Replacing the 54 requires you to also use the getWidth() method of the piano’s image. After doing this, our code will always place the keys nicely, even if their size changes.
Our code now places our white keys nicely—that’s a good step forward. The most obvious prob- lem now is that all piano keys react to the same keyboard key and play the same note. Fixing this again requires a new programming construct: an array.