Java 101: Foundations

Java 101: Deciding and iterating with Java statements

Use statements to make decisions, iterate, and perform other tasks in your Java programs

1 2 3 Page 2
Page 2 of 3

The variable that controls the loop can be a different primitive type, such as Boolean, character, or double precision floating-point. Here are three examples:

for (boolean b = false; b != true; b = !b)
   System.out.println(b); // This statement executes once.

for (char c = 'A'; c <= 'F'; c++)
   System.out.println(c);

for (double d = 0.0; d < 1.0; d += 0.1)
   System.out.println(d);

Finally, as previously mentioned, the initialize section can declare multiple variables. The following example declares two variables, incrementing one variable and decrementing the other variable throughout the loop:

for (int i = 0, j = 5; i <= 5; i++, j--)
   System.out.println(i + j);

The output consists of six lines of 5.

The while statement

The while statement repeatedly executes another statement while its controlling Boolean expression keeps evaluating to true. This statement has the following syntax:

while (Boolean expression)
   statement

This syntax shows that a while statement begins with the reserved word while and continues with a parenthesized Boolean expression. This statement is followed by another statement to execute repeatedly.

The following example demonstrates the while statement:

int i = 0;
while (i < args.length)
{
   System.out.println(args[i]);
   i++;
}

This example works as follows:

  1. Declare variable i and initialize it to 0.
  2. Evaluate i < args.length. If i equals args.length, terminate the loop.
  3. Execute System.out.println(args[i]);.
  4. Execute i++.
  5. Continue with Step 2.

This example is the while equivalent of the previous for example. You could compact the example to repeatedly execute a simple statement instead of a compound statement, as follows:

int i = 0;
while (i < args.length)
   System.out.println(args[i++]);

In this compacted example, I've changed the postincrement statement to an expression that's passed to the array index operator. Although the code is more compact, you might prefer the previous example for clarity.

The do-while statement

The do-while statement repeatedly executes a statement while its controlling Boolean expression, which is evaluated after the statement is executed, evaluates to true. This statement has the following syntax:

do
   statement
while (Boolean expression); // The semicolon terminator is mandatory.

This syntax shows that a do-while statement begins with reserved word do, continues with a statement to execute repeatedly, and ends with reserved word while, followed by a parenthesized Boolean expression.

The following example demonstrates the do-while statement:

int ch;
do
{
   System.out.println("Press x to continue.");
   ch = System.in.read();
}
while (ch != 'x');

This example works as follows:

  1. Declare int variable ch to store a character's numeric code.
  2. Prompt the user to press the x key to continue.
  3. Read a key code from the keyboard via System.in.read(), which is a companion of System.out.println(). Because this method returns the key's code as an int, assign this value to ch.
  4. Compare ch's value with 'x'. Note that 'x' is widened from char to int before the comparison. Terminate the loop when this expression evaluates to false (ch equals 'x'). Otherwise, continue with Step 2.

The difference between while and do-while is that while executes its statement zero or more times, whereas do-while executes its statement one or more times. You will choose either statement based on this property. For example, it's appropriate to use while to iterate over the args array because this array might have zero length and you don't want to access the array in this case (and raise an out-of-bounds exception, which is discussed in a future article). In contrast, you would access the array at least once with do-while (and raise an out-of-bounds exception). It's appropriate to use do-while to prompt the user to enter a key and read the response because these tasks must happen at least once.

Breaking out of and continuing iteration

You previously saw the break statement in the context of a switch statement, for breaking out of a switch statement once a case has executed. However, this statement also can be used in an iteration statement context, which I discuss in this section. I also discuss the continue statement, which can be used in an iteration statement context only. You will explore the unlabeled and labeled versions of these statements.

The unlabeled break and labeled break statements

The unlabeled break statement terminates a switch, for, while, or do-while statement by transferring execution to the first statement following this statement. It has the following syntax:

break;

The following example demonstrates the unlabeled break statement in an iteration statement context:

for (; ;)
{
   System.out.println("Press x to continue.");
   int ch = System.in.read();
   if (ch == 'x')
      break;
}

This example introduces a for-based infinite loop that repeatedly prompts the user to press the x key and reads this key until it equals 'x'. An if statement performs the comparison, executing break; to terminate the loop when the x key is pressed.

The labeled break statement terminates a containing and labeled switch, for, while, or do-while statement by transferring execution to the first statement following the containing statement. It has the following syntax:

break label;

This syntax consists of reserved word break followed by a non-reserved word identifier to serve as a label, followed by a semicolon. The label must be prefixed to a previous switch or iteration statement and must be followed by a colon.

The following example demonstrates the labeled break statement in an iteration statement context:

outer:
while (true)
{
   System.out.println("Guess number between 0 and 9.");
   while (true)
   {
      System.out.println("Press n for new game or q to quit.");
      int ch = System.in.read();
      if (ch == 'n')
         break;
      if (ch == 'q')
         break outer;
   }
}

This example presents a pair of nested infinite while loops that describe part of a number-guessing game. The outer loop is a stub for playing the game, whereas the inner loop prompts the user to play a new game or quit the game.

If the user presses the n key, the unlabeled break statement is executed to terminate the inner loop so that a new game can be played. If q is pressed, break outer; is executed to quit the outer loop, which is assigned an outer: label.

The unlabeled continue and labeled continue statements

The unlabeled continue statement skips the remainder of the current iteration and tells the iteration statement to advance to the next iteration. It has the following syntax:

continue;

Here's an example usage of the unlabeled continue statement:

for (int i = -2; i <= 2; i++)
   if (i == 0)
      continue;
   else
      System.out.println(10 / i);

This example's for statement iterates from -2 to 2, repeatedly executing an if-else statement and then incrementing i by 1 after each iteration.

To prevent a divide-by-zero exception when i contains 0, if tests i for 0. If this is the case, it executes continue;, which causes for to increment i and then evaluate i <= 2. Otherwise, 10 / i is evaluated and the result is output.

The labeled continue statement skips the remaining iterations of one or more nested iteration statements and transfers execution to the labeled iteration statement. It has the following syntax:

continue label;

This syntax consists of reserved word continue followed by a non-reserved word identifier to serve as a label, followed by a semicolon. The label must be prefixed to a previous iteration statement and must be followed by a colon.

Here's an example using the labeled continue statement:

outer:
for (int i = -2; i <= 2; i++)
   for (int j = -2; j <= 2; j++)
      if (i == 0)
         continue outer;
      else
      if (j == 0)
         continue;
      else
         System.out.println(10 / i * j);

This example presents a pair of nested for loops, with each loop variable ranging from -2 through 2. The idea is to divide 10 by the product of the loop variable values. However, division by zero will occur when either variable contains 0.

To prevent division by zero, a chained if-else statement is used to test i's and j's values for 0. If i's value is 0, continue outer; is used to terminate the inner loop and advance the outer loop (with label outer:) past 0. If j's value is 0, continue; is used to quit the current inner loop iteration and advance the inner loop past 0. If neither situation arises, the calculation is performed and its result is output.

Doing nothing

There is one final statement to consider, which is the empty statement, a statement consisting solely of the semicolon character. This statement accomplishes nothing, and yet it is useful. Consider the following example:

for (int ch; (ch = System.in.read()) != -1; System.out.print((char) ch));

This example copies the contents of the standard input stream, read via calls to System.in.read(), to the standard output stream, written via calls to System.out.print(), a companion to System.out.println() that doesn't output a line separator. It works best when the standard input stream is redirected from the keyboard to a text file.

When redirected to a file, System.in.read() returns -1 when there is no more input. When not redirected, System.in.read() obtains its input from the keyboard and never returns -1. Instead, when there are no more key codes to return, System.in.read() returns a line separator character -- two calls are needed on Windows to return its \r\n characters, one call is needed on Unix\Linux to return its \n character, and one call is needed on older versions of Mac OS to return its \r character. For more information, check out Newline.

As you can see, all of the work is performed in the for statement's initialize and test sections. The final semicolon refers to the empty statement, which is executed repeatedly.

Be careful with the empty statement because it can be the source of hard-to-find bugs. For example, you might expect the following for statement to output 10 instances of the word Hello:

for (int i = 0; i < 10; i++);
   System.out.println("Hello");

Instead, you will only observe a single instance of this word, because of the empty statement after the for statement's closing parenthesis. for executes the empty statement 10 times, after which the method call is executed once.

Writing interesting applications

Now that you've explored all of Java's fundamental language features, you're ready to start creating interesting applications. For example, consider a guess-the-number game that randomly selects an integer ranging from 0 through 9 and asks you to guess this number. If you guess too high or too low, the game will tell you. It will also tell you when you guess correctly, and will ask you if you want to play again.

Before I present the game application's source code, I need to introduce you to two features in this source code that you haven't yet encountered:

  • I use System.in.read() to return either the code of a pressed key (when standard input is not redirected) or an 8-bit value from a file (when standard input is redirected). System.in.read() is capable of throwing an exception, so I had to append "throws Exception" to the main() method header, as in public static void main(String[] args) throws Exception. This prevents the compiler from reporting an error.
  • To obtain a random integer, I need to invoke the random() method member of the standard class library's Math class. random() returns a floating-point value ranging from 0.0 to almost 1.0. An expression converts this number to a more useful integer.

Listing 1 presents the source code to the Guess application.

1 2 3 Page 2
Page 2 of 3