Section 2.7
Details of Control Statements


JAVA HAS THREE CONTROL STRUCTURES for doing loops: the while loop, the do loop, and the for loop. It has two control structures for branching: the if statement and the switch statement. This section covers the details of these statements.


The do Loop

You've already seen the while statement, in which the computer tests a condition at the beginning of the loop, to determine whether it should continue looping:

           while ( boolean-expression )
              statement

The do loop is a variation of this in which the test comes at the end. It takes the form:

          do
              statement
          while ( boolean-expression );

or, since as usual the statement can be a block,

          do {
              statements
          } while ( boolean-expression );

(Note the semicolon, ';', at the end. This semicolon is part of the statement, just as the semicolon at the end of an assignment statement or declaration is part of the statement. More generally, every statement in Java ends either with a semicolon or a right brace, '}'.)

To execute a do loop, the computer first executes the body of the loop -- that is, the statement or statements inside the loop -- and then evaluates the boolean expression. If the value of the expression is true, the computer returns to the beginning of the do loop and repeats the process; if the value is false, it ends the loop and continues with the next part of the program.

The main difference between the do loop and the while loop is that the body of a do loop is executed at least once, before the boolean expression is ever evaluated. In a while loop, if the boolean expression is false when the computer first checks it, then the body of the loop will never be executed at all.

For example, consider the following pseudocode for a game-playing program. The do loop makes sense here instead of a while loop because with the do loop, you know there will be at least one game. Also, the test that is used at the end of the loop wouldn't even make sense at the beginning:

         do {
            Play a Game;
            Ask user if he wants to play another game;
         } while ( the user's response is yes );

The for Loop

The for loop exists to make a common type of while loop easier to write. Many while loops have the same general form:

            initialization
            while ( continuation-condition ) {
                statements
                update
            }

For example, consider

            int years = 0;  // initialize the variable years
            while ( years < 5 ) {   // condition for continuing loop
                interest = principal * rate; // do some statements
                principal += interest;
                System.out.println(principal);
                years++;   // update the value of the variable years
            }

This loop can be written as the following for statement:

            for ( int years = 0;  years < 5;  years++ ) {
               interest = principal * rate;
               principal += interest;
               System.out.println(principal);
            }

The initialization, continuation condition, and updating have all been combined in the first line of the for loop. This keeps everything involved in the "control" of the loop in one place, which helps makes the loop easier to read and understand. In general, a for loop takes the form:

            for ( initialization; continuation-condition; update )
                 statement

or, using a block statement,:

            for ( initialization; continuation-condition; update ) {
                 statement
            }

The continuation-condition must be a boolean-valued expression. The initialization can be any expression, as can the update. Any of the three can be empty. Usually, the initialization is an assignment or a declaration, and the update is an assignment or an increment or decrement operation. The official syntax actually allows the initialization and the update to consist of several expressions, separated by commas. If you declare a variable in the initialization section, the scope of that variable is limited to the for statement; that is, it is no longer valid after the for statement is ended.

Here are a few examples of for statements:

          // print out the alphabet on one line of output
          for ( char ch='A'; ch <= 'Z';  ch++ )
              console.put(ch);
          console.putln();
          
          // count up to 10 and down from 10 at the same time
          for ( int i=0,j=10;  i < 10;  i++,j-- ) {
             console.put(i,5);  // output i in a 5-character wide column
             console.putln(j,5);
          }
          
          // compute the number 1 * 2 * 3 * ... * 20
          long factorial = 1;
          for (int num=2; num <= 20; num++)
             factorial *= num;
          System.out.println("20! = " + factorial);

The break Statement

The syntax of the while, do, and for loops allows you to make a test at either the beginning or at the end of the loop to determine whether or not to continue executing the loop. Sometimes, it is more natural to have the test in the middle of the loop, or to have several tests at different places in the same loop. Java provides a general method for breaking out of the middle of any loop. It's called the break statement, which takes the form

break;

When the computer executes a break statement, it will immediately jump out of the loop (or other control structure) that contains the break. It then continues on to whatever follows the loop in the program. Consider for example:

            while (true) {  // looks like it will run forever!
               console.put("Enter a positive number: ");
               N = console.getlnt();
               if (N > 0)   // input is OK; jump out of loop
                  break;
               console.putln("Your answer must be > 0.");
            }
            // continue here after break

A break statement terminates the loop that immediately encloses the break statement. It is possible to have nested loops, where one loop statement is contained inside another. If you use a break statement inside a nested loop, it will only break out of that loop, not out of the loop that contains the nested loop. There is something called a "labeled break" statement that allows you to specify which loop you want to break. I won't give the details here; you can look them up if you ever need them.


More on the if Statement

I have already discussed the if statement in Section 3. It takes the form

             if (boolean-expression)
                  statement-1
             else
                  statement-2

As usual, the statements inside an if statements are often blocks. The if statement represents a two-way branch. The else part of an if statement -- consisting of the word "else" and the statement that follows it -- can be omitted.

Now, an if statement is, in particular, a statement. This means that either statement-1 or statement-2 inside an if statement can itself be an if statement. (Note: If statement-1 is an if statement, then it has to have an else part; if it does not, the computer will mistake the "else" of the main if statement for the missing "else" of statement-1. This is called the dangling else problem. You can avoid this problem by enclosing statement-1 between { and }, making it into a block.)

An if statement in which the else part is itself an if statement would look like this (perhaps without the final else part):

             if (boolean-expression-1)
                  statement-1
             else
                  if (boolean-expression-2)
                      statement-2
                  else
                      statement-3

However, since the computer doesn't care how a program is laid out on the page, this is usually written in the format:

             if (boolean-expression-1)
                  statement-1
             else if (boolean-expression-2)
                  statement-2
             else
                  statement-3

You should think of this as a single statement representing a three-way branch. When the computer executes this, one and only one of the three statements, statement-1, statement-2, and statement-3, will be executed. The computer starts by evaluating boolean-expression-1. If it is true, the computer executes statement-1 and then jumps all the way to the end of the big if statement, skipping the other two statement's. If boolean-expression-1 is false, the computer skips statement-1 and executes the second, nested if statement. That is, it tests the value of boolean-expression-2 and uses it to decide between statement-2 and statement-3.

Here is an example that will print out one of three different messages, depending on the value of a variable named temperature:

            if (temperature < 50)
               System.out.println("It's cold.");
            else if (temperature < 80)
               System.out.println("It's nice.");
            else
               System.out.println("It's hot.");

If temperature is, say, 42, the computer prints out the message "It's cold", and skips the rest -- without even evaluating the second condition.

You can go on stringing together "else-if's" to make multiway branches with any number of cases:

             if (boolean-expression-1)
                  statement-1
             else if (boolean-expression-2)
                  statement-2
             else if (boolean-expression-3)
                  statement-3
               .
               . // (more cases)
               .
             else if (boolean-expression-N)
                  statement-N
             else
                  statement-(N+1)

You should just remember that only one of the statements will be executed and that the computer will stop evaluating boolean-expressions as soon as it finds one that is true. Also, remember that the final else part can be omitted and that any of the statements can be blocks, consisting of a number of statements enclosed between { and }. (Admittedly, there is lot of syntax here; as you study and practice, you'll become comfortable with it.)


The switch Statement

Java also provides a control structure that is specifically designed to make multiway branches of a certain type: the switch statement. A switch statement allows you to test the value of an expression and, depending on that value, to jump to some location within the switch statement. The positions you can jump to are marked with "case labels" that take the form: "case constant:". This marks the position the computer jumps to when the expression evaluates to the given constant. As the final case in a switch statement you can, optionally, use the label "default:", which provides a default jump point that is used when the value of the expression is not listed in any case label.

A switch statement has the form:

          switch (integer-expression) {
             case integer-constant-1:
                statements-1
                break;
             case integer-constant-2:
                statements-2
                break;
                .
                .   // (more cases)
                .
             case integer-constant-N:
                statements-N
                break;
             default:  // optional default case
                statements-(N+1)
          } // end of switch statement

The break statements are technically optional. The effect of a break is to make the computer jump to the end of the switch statement. If you leave out the break statement, the computer will just forge ahead after completing one case and will execute the statements associated with the next case label. This is rarely what you want, but it is legal. (I will note here -- although you won't understand it until you get to the next chapter -- that inside a subroutine, the break statement is sometimes replaced by a return statement.)

Note that you can leave out one of the groups of statements entirely (including the break). You then have two case labels in a row, containing two different constants. This just means that the computer will jump to the same place and perform the same action for each of the two constants.

Here is an example of a switch statement. This is not a useful example, but it should be easy for you to follow. Note, by the way, that the constants in the case labels don't have to be in any particular order, as long as they are all different:

          switch (N) {   // assume N is an integer variable
             case 1:
                System.out.println("The number is 1.");
                break;
             case 2:
             case 4:
             case 8:
                System.out.println("The number is 2, 4, or 8.");
                System.out.println("(That's a power of 2.)");
                break;
             case 3:
             case 6:
             case 9:
                System.out.println("The number is 3, 6, or 9.");
                System.out.println("(That's a multiple of 3.)");
                break;
             case 5:
                System.out.println("The number is 5.");
                break;
             default:
                System.out.println("The number is 7,");
                System.out.println("   or is outside the range 1 to 9.");
          }

The switch statement is pretty primitive as control structures go, and it's easy to make mistakes when you use it. Java takes all its control structures directly from the older programming languages C and C++. The switch statement is certainly one place where the designers of Java should have introduced some improvements.


The Empty Statement

As a final note in this section, I will mention one more type of statement in Java: the empty statement. This is a statement that consists simply of a semicolon. The existence of the empty statement makes the following legal, even though you would not ordinarily see a semicolon after a }.

             if (x < 0) {
                 x = -x;
             };

The semicolon is legal after the }, but the computer considers it to be an empty statement. Occasionally, you might find yourself using the empty statement when what you mean is, in fact, "do nothing". I prefer, though, to use an empty block, consisting of { and } with nothing between, for such cases.


A List of Java Statement Types

I mention the empty statement here mainly for completeness. You've now seen just about every type of Java statement. A complete list is given below for reference. The only new items in the list are the try...catch and synchronized statements, which are related to advanced aspects of Java known as exception-handling and multithreading.

Another possible surprise in the list is what I've listed as "other expression statement," which reflects the fact that any expression followed by a semicolon can be used as an expression. To execute such a statement, the computer simply evaluates the expression, and then ignores the value. Of course, this only makes sense when the evaluation has a side effect that makes some change in the state of the computer. An example of this is the expression statement "x++;", which has the side effect of adding 1 to the value of x. Note that, technically, assignment statements and subroutine call statements are also considered to be expression statements.

Java statement types:


[ Next Section | Previous Section | Chapter Index | Main Index ]