Learn Programming in Java


<<Previous | ToC | Next >>

Lesson #4: Iteration

Last time we built a simple guessing game program. Did you experiment with changing the approved range? What happened when there were more than 8 possible numbers? We had three identical sequences of question followed by input, wouldn't it be easier if the computer did the same thing over and over again? That's called iteration, or more often a loop, and it's a very important programming tool. But you knew that from the Kitchen computer.

The basic way to tell a Java program to repeat the same thing over and over is called "while" and we give it a condition for doing whatever we want it to repeat. If the condition is true, it does the body of the loop and then looks again, otherwise it goes on to the next statement after the while loop. It's important that somewhere in the body the condition eventually gets turned off, otherwise the program never gets out of the loop.

One of the two most common kinds of loop is where you want to do it a certain number times like the repeat in the Kitchen computer, but in Java you set a variable to count those times through, then increment the counter inside the body, and test for whether it's still less than the number of times you want, like this:

int n = 0;
while (n<7) { // repeats a total of seven times, first n=0, then n=1, ... finally n=6
    // do something, possibly involving n
    n++;
} // end of while


This is so common that Java has some "syntactic sugar" (a different way to spell the same thing) that makes your intentions more obvious. Notice that I colored the different parts of the for loop to match their corresponding parts of the while loop structure:

for (int n = 0; n<7; n++) {
    // do something, possibly involving n
} // end of for


You can also use an existing variable and omit the declaration inside the parentheses: "for (n=0; n<7; n++)". It is important to understand that this is only a different spelling for the while loop, you could change the value of the control variable n inside the loop, which would totally mess up the number of times the loop runs, but you must resist the temptation to do that. Better languages than C or Java won't let you change the control variable inside the loop, but this is the real world we live in. You will make mistakes, and Java won't help you with this particular one.

The other common kind of loop is controlled by some outside condition, like whether input has arrived or an error occurred. There is no control variable to increment, but there must be some testable condition, or again the loop never comes out. That's not always bad, sometimes -- especially with a program controlling hardware -- the program never has any reason to stop, so you would code it as "while (true) ..." I do that a lot, but there is another way out of a loop that has not met the exit condition but you still want out now, and that is called "break;" (like the exit in the Kitchen computer) because it breaks out of the loop no matter what. In my programs I write a lot of while(true) loops that exit by means of the break statement. I often use the structure instead of nested if/else statements when my conditions don't nest nicely. In the same place you use break you can instead use continue to jump to the next iteration.

Most programmers think of the braces ("{}") as being part of the obligatory loop structure -- and that's probably a good habit to get into -- but in reality Java expects the while- and for-loop to have a single statement after the right parenthesis, so if that's all you have, then you don't need the braces. The same is true of if and else. The sample code you see from me may or may not have braces, depending on whatever is convenient. Here are some examples of goofy but valid while and for loops:

while (false) ; // null statement executed never
while (false) {} // same thing (sometimes also called a "stub")
for (i=0;i>4;i++) {} // same idea, but nore complicated
for (i=9;i>0;i--) z++; // control variable counts down while z counts up
while (true) break; // executes once, but breaks out immediately
for (;true;) break; // same idea, as a for-loop


Part of being a good programmer is knowing what differences matter, and what doesn't. For example, sometimes I put the ending right brace on a separate line, sometimes I put it at the end of the last line it encloses (but before any comment). Java doesn't care, but I get to look at more of my program (without scrolling) when there are fewer one-brace lines. On the other hand, it's easier to find missing braces when they are spread out. Some program editors (including BlueJ, when you click to the right of the brace) help you find matching braces. It's a problem plaguing all programmers, so the editors mostly all help you find the other brace.

Now let's look at that guessing game again. Recall there were five lines of code repeated exactly three times. One important quality of being a good programmer is knowing when and how to re-use code. Any time you have the same or very similar code showing up in different parts of your program -- or especially in the same place, like here -- we want to re-use a single piece of code in all those places. A loop is one way to do that: throw two of those copies away and re-use the remaining copy three times by putting those five lines into a loop. We could use a for-loop to do the five lines exactly three times, but if you experimented with different value ranges, you can now appreciate why we might not want to do that. Let's set the exit condition of a while-loop to be that the range has been reduced to zero, that is, (hi==lo) which means that we do the loop again so long as (hi>lo) like this:

    int hi = 8, lo = 1, mid;
    char ans;
    System.out.println("Think of a number between " + lo + " and " + hi);
    while (hi>lo) {
      mid = (hi+lo)/2; // initial test @ 4
      System.out.print("Is your number greater than " + mid + " (y/n)? ");
      ans = Zystem.ReadLetter();
      if (ans == 'y') lo = mid+1;
        else hi = mid;
    } // end of questioning while
    if (hi==lo) System.out.println("Your number is " + hi);
      else System.out.println("Oops something went wrong");


As written, it should work the same as it did before. Except the BlueJ console input accepts only lines terminated by the Enter key, and Zystem.ReadLetter passes that Enter along as a separate input character, which is the same problem as when the user types in something other than 'y' or 'n'. You can verify that the input character is what you want (which the above program does not), but you need some way to go back for another try. That part of the program is already inside a loop, but the beginning of the loop finds a new midpoint, even if the previous answer is invalid.

There are several possible solutions, two come readily to my mind: Most obvious is to make another loop around the input and the validity test, which stays there until the user responds correctly. Have you ever tried to fill out a form where the computer refused to accept the correct answer? This one is not that bad, they can hit either 'y' or 'n' and the question is not something utterly Wrong like "Have you stopped killing people?" You probably want to include the prompt message in the loop so the user can see that the program is still waiting for valid input.

The other simple solution is to add a conditional to the midpoint calculation, so it's disabled if the previous answer was neither 'y' nor 'n', and then just do the loop over if the answer is unacceptible. You could create another variable (perhaps boolean ok initialized =true both at the beginning where it is declared, and again after it is used, then set =false if the input is invalid. This would make the program most readable. Me, I would look around and see another existing variable that can be given an alternative value to serve the same purpose, because that would not interfere with its purpose elsewhere in the program. Pick something you like and understand and write it into your program.

Now suppose you make the high end of the range larger, like "hi = 99"? Then it automatically asks its question three or four more times. Do you understand why? You need to convince yourself that you understand why it does what it does. I call it "thinking like a computer," and you will never get to be a good programmer without it. Run it in the debugger if necessary.

Now let's do a game that's a little more interesting, Rock-Paper-Scissors. Real people play it with hand motions, no words needed, but the computer does not have hands that can do those motions (we could do it with video, but this is about programming in Java, not scripting movie segments ;-) and while most computers have a camera, extracting the hand motions from that video stream is very hard. So we will do it with text: the computer will decide its play then ask you for yours, then the computer will keep score. Think about how you would do it, before going to the next page...

Next: Rock-Paper-Scissors

<<Previous | ToC | Next >>

Revised: 2021 July 15