Give a second chance

By now you've created a program that prompts the user for various kinds of input. But what if the user messes up and types the wrong thing. At this point the only thing he can do is restart the program. We will overcome this in this chapter by learning about a very important programming feature called "while loops".

Loops

"while" loops

Loops allow us to run a particular line of code more than once. The while loop is the simplest loop. A while loop looks very similar to the "if" statement.
while (someCondition) {
    someStatement;
    someOtherStatement;
    ...
}
While loops behave like "if" statements in that the body (enclosed in braces) is not executed unless the condition evaluates to true. The difference is that with "while" loops, the body is continually executed while the condition evaluates to true, not just once. Let's go back to our introduction sequence again and see how "while" loops can make our program more user friendly:
public class Stakeout {

    public static void main (String args[]) throws java.io.IOException {
        bool invalidNumUsers = true;
        while (invalidNumUsers) {
            System.out.println ("How many players do you want to use? [2, 3, or 4]");
            String input = CmdInput.GetInput ();
            if (input.contentEquals ("2")) {
                System.out.println ("Two players it is!");
                invalidNumUsers = false;
            }
            else if (input.contentEquals ("3")) {
                System.out.println ("Three players it is!");
                invalidNumUsers = false;
            }
            else if (input.contentEquals ("4")) {
                System.out.println ("Four players it is!");
                invalidNumUsers = false;
            }
            else {
                System.out.println ("You entered an invalid number of players!");
            }
        }
        System.out.println ("Game over!");
    }
}
First we initialize the condition (which is just a simple boolean) to true. Since the condition is true, we immediately jump into the loop and begin executing the statements starting from the top in the same way as we do with "if" statements except that when it gets to the bottom of the while loop it re-checks the invalidNumUsers condition. If the condition is true, it starts back at the top of the while loop and begins executing the satements again. If it's false (which will happen if any of our "invalidNumUsers = false" statements are run), it picks up after the end of the while loop and executes the final println statement. Notice that we no longer need to exit when the user enters invalid input because the program will re-prompt the user for valid input. It's important that somewhere in our loop we set "invalidNumUsers = false" because otherwise our program will never end and the user will have to kill it manually.

"break" statements

There is another way to break out of a loop that will remove the need for the invalidNumUsers variable and will be useful in other situations later on. It is called the "break" statement. We can put a break statement anywhere in our "while" loop and if it gets executed, the program will immediately exit the loop.
public class Stakeout {

    public static void main (String args[]) throws java.io.IOException {
        while (true) {
            System.out.println ("How many players do you want to use? [2, 3, or 4]");
            String input = CmdInput.GetInput ();
            if (input.contentEquals ("2")) {
                System.out.println ("Two players it is!");
                break;
            }
            else if (input.contentEquals ("3")) {
                System.out.println ("Three players it is!");
                break;
            }
            else if (input.contentEquals ("4")) {
                System.out.println ("Four players it is!");
                break;
            }
            else {
                System.out.println ("You entered an invalid number of players!");
            }
        }
        System.out.println ("Game over!");
    }
}
As you can see, the loop condition will always evaluate to true, but if we get valid input, we will immediately jump out of the loop and continue at the last println statement producing the same effect that we saw before.

Scope

Observe how, in the above example, the input String is declared inside of the "while" statement. The innermost braces enclosing a variable declaration is called it's scope. That variable cannot be referred to outside of that scope. This applies to any braces in the program, not just braces used with "while" statements. If we tried to compile the following code...
public class Stakeout {

    public static void main (String args[]) throws java.io.IOException {
        while (true) {
            System.out.println ("How many players do you want to use? [2, 3, or 4]");
            String input = CmdInput.GetInput ();
            if (input.contentEquals ("2")) {
                System.out.println ("Two players it is!");
                break;
            }
            else if (input.contentEquals ("3")) {
                System.out.println ("Three players it is!");
                break;
            }
            else if (input.contentEquals ("4")) {
                System.out.println ("Four players it is!");
                break;
            }
            else {
                System.out.println ("You entered an invalid number of players!");
            }
        }
        
System.out.println ("You entered: " + input);
System.out.println ("Game over!"); } }
We would get an error because we are referring to the input variable outside of its scope. To fix this problem we simply move the declaration of this variable out to the main function's scope and the problem goes away.
public class Stakeout {

public static void main (String args[]) throws java.io.IOException {
        
String input;
while (true) { System.out.println ("How many players do you want to use? [2, 3, or 4]"); input = CmdInput.GetInput (); if (input.contentEquals ("2")) { System.out.println ("Two players it is!"); break; } else if (input.contentEquals ("3")) { System.out.println ("Three players it is!"); break; } else if (input.contentEquals ("4")) { System.out.println ("Four players it is!"); break; } else { System.out.println ("You entered an invalid number of players!"); } }
System.out.println ("You entered: " + input);
System.out.println ("Game over!"); } }
Now the input variable is declared at the function scope and therefore can be used anywhere within the function as long as it occurs after the declaration.

There are other ways of prompting the user multiple times for input without using loops, but we will only be able to prompt a finite number of times and it would result in a lot of redundant (copied) code. Here's an example prompting the user 3 times:
public class Stakeout {

public static void main (String args[]) throws java.io.IOException {
        String input;
        System.out.println ("How many players do you want to use? [2, 3, or 4]");
        input = CmdInput.GetInput ();
        if (input.contentEquals ("2")) {
            System.out.println ("Two players it is!");
            break;
        }
        else if (input.contentEquals ("3")) {
            System.out.println ("Three players it is!");
            break;
        }
        else if (input.contentEquals ("4")) {
            System.out.println ("Four players it is!");
            break;
        }
        else {
            System.out.println ("You entered an invalid number of players!");
            System.out.println ("How many players do you want to use? [2, 3, or 4]");
            input = CmdInput.GetInput ();
            if (input.contentEquals ("2")) {
                System.out.println ("Two players it is!");
                break;
            }
            else if (input.contentEquals ("3")) {
                System.out.println ("Three players it is!");
                break;
            }
            else if (input.contentEquals ("4")) {
                System.out.println ("Four players it is!");
                break;
            }
            else {
                System.out.println ("You entered an invalid number of players!");
                System.out.println ("How many players do you want to use? [2, 3, or 4]");
                input = CmdInput.GetInput ();
                if (input.contentEquals ("2")) {
                    System.out.println ("Two players it is!");
                    break;
                }
                else if (input.contentEquals ("3")) {
                    System.out.println ("Three players it is!");
                    break;
                }
                else if (input.contentEquals ("4")) {
                    System.out.println ("Four players it is!");
                    break;
                }
                else {
                    System.out.println (
                        "Sorry, you entered an invalid number of players."
                    );
                    System.out.println ("Exiting...");
                    System.exit (0);
                }
            }
        }
    
        System.out.println ("Game over!");
    }
}
This makes for a maintenance nightmare. If, for example, we decide to change our prompt message from "You entered an invalid number of players!" to something slightly different, we'd have remember to change it in 3 different places! Whereas in the code where we used loops, we would only have to change the text in one place.

Loops are also useful for other things. If we needed to perform the same calculation multiple times, we could use a loop. Remember when we were doubling the number of units a few lessons ago? This could be done much easier with a loop:
public class Stakeout {
    public static void main (String args[]) {
        int numUnits = 1;
        while (numUnits < 100) {
            System.out.println ("The value is " + numUnits);
            numUnits = numUnits * 2;
        }
    }
}
This will multiply the numUnits variable by two until it gets to be greater than or equal to 100. At that point the condition will be false and the looping will stop.

Follow-up exercise

Rewrite your introduction sequence from the last lesson, but use loops to re-prompt the user for input if he entered an invalid value.


Rate this lesson: *****