Loop, switch, or take a break? Deciding and iterating with Java statements

how-to
May 01, 201929 mins
Core JavaJavaProgramming Languages

Learn how to use standby statements like for, while, if-else, and break, then get started with the new switch expressions in Java 12

speech bubble
Credit: Thinkstock

Java applications evaluate expressions in the context of statements, which are used for tasks such as declaring a variable, making a decision, or iterating over statements. A statement can be expressed as a simple or a compound statement:

  • A simple statement is a single standalone instruction for performing a task; it must be terminated with a semicolon character (;).
  • A compound statement is a sequence of simple and other compound statements located between open- and close-brace characters ({ and }), which delimit the compound statement’s boundaries. Compound statements can be empty, will appear wherever simple statements appear, and are alternatively known as blocks. A compound statement is not terminated with a semicolon.

In this tutorial, you’ll learn how to use statements in your Java programs. You can use statements such as if, if-else, switch, for, and while to declare variables and specify expressions, make decisions, iterate (or loop) over statements, break and continue iteration, and more. I’ll leave some of the more exotic statements–such as statements for returning values from called methods and for throwing exceptions–for future Java 101 tutorials.

download
Download the source code for example applications in this tutorial. Created by Jeff Friesen for JavaWorld.

Variable declarations and assignments

I’ve previously introduced Java variables and explained that they must be declared before being used. Because a variable declaration is a standalone island of code, it’s effectively a statement–a simple statement, to be exact. All of these are variable declaration statements:

int age = 25;
float interest_rate;
char[] text = { 'J', 'a', 'v', 'a' };
String name;

A variable declaration minimally consists of a type name, optionally followed by a sequence of square-bracket pairs, followed by a name, optionally followed by a sequence of square-bracket pairs, and terminated with a semicolon. A variable may also be explicitly initialized during its declaration.

Now consider the assignment statement, which is closely related to the variable declaration statement. An assignment statement assigns a value (possibly a reference to an array or a reference to an object) to a variable. Here are some examples:

age = 30;
interest_rate = 4.0F;
age += 10;
text[1] = 'A';
text[2] = 'V';
text[3] = 'A';
name = "John Doe";

An assignment statement is an example of an expression statement, which is an expression that may be used as a statement if it is followed with a semicolon. The following expressions also qualify as expression statements:

  • Preincrement (e.g., ++x;)
  • Predecrement (e.g., --y;)
  • Postincrement (e.g., x++;)
  • Postdecrement (e.g., y--;)
  • Method call (e.g., System.out.println("Hello");)
  • Object creation (e.g., new String("ABC");)

Variable declarations with jshell

You can use jshell to experiment with variable declarations and expression statements. Here are some examples to get you started (see “Learn Java from the ground up” for an introduction to the Java Shell):

jshell> int age = 25
age ==> 25

jshell> float interest_rate
interest_rate ==> 0.0

jshell> char[] text = { 'J', 'a', 'v', 'a' }
text ==> char[4] { 'J', 'a', 'v', 'a' }

jshell> String name
name ==> null

jshell> age = 30
age ==> 30

jshell> interest_rate = 4.0F
interest_rate ==> 4.0

jshell> age += 10
$7 ==> 40

jshell> text[1] = 'A'
$8 ==> 'A'

jshell> text[2] = 'V'
$9 ==> 'V'

jshell> text[3] = 'A'
$10 ==> 'A'

jshell> name = "John Doe"
name ==> "John Doe"

jshell> text
text ==> char[4] { 'J', 'A', 'V', 'A' }

jshell> age++
$13 ==> 40

jshell> age
age ==> 41

Notice that age++ doesn’t appear to have accomplished anything. Here, you see that 40 has been assigned to the scratch variable $13. However, the postincrement operator performs the increment after returning the current value. (Actually, it stores the current value somewhere, performs the increment, and then returns the stored value.) Entering age proves that age contains 41, the result of the postincrement operation.

The Java Shell provides various commands and features that simplify working with snippets. For example, the /list command shows all snippets that have been entered in the current session:

jshell> /list

   1 : int age = 25;
   2 : float interest_rate;
   3 : char[] text = { 'J', 'a', 'v', 'a' };
   4 : String name;
   5 : age = 30
   6 : interest_rate = 4.0F
   7 : age += 10
   8 : text[1] = 'A'
   9 : text[2] = 'V'
  10 : text[3] = 'A'
  11 : name = "John Doe"
  12 : text
  13 : age++
  14 : age

The number in the left column uniquely identifies a snippet. You can use this number to re-execute a snippet, list the snippet, drop (delete) a snippet, and so on:

jshell> /12
text
text ==> char[4] { 'J', 'A', 'V', 'A' }

jshell> /list 13

  13 : age++

jshell> /drop 7
|  dropped variable $7

jshell> /list

   1 : int age = 25;
   2 : float interest_rate;
   3 : char[] text = { 'J', 'a', 'v', 'a' };
   4 : String name;
   5 : age = 30
   6 : interest_rate = 4.0F
   8 : text[1] = 'A'
   9 : text[2] = 'V'
  10 : text[3] = 'A'
  11 : name = "John Doe"
  12 : text
  13 : age++
  14 : age
  15 : text

Here we’ve entered /12 to re-execute snippet #12, which outputs the contents of text. We then entered /list 13 to list snippet #13, which increments age. Next, we entered /drop 7 to delete snippet #7 (no more age += 10 snippet). Finally, we entered /list to re-list all snippets. Notice that snippet #7 has been removed, and a snippet #15 has been added thanks to the /12 command.

Making decisions: if, if-else, and switch

Decision statements let applications choose between multiple paths of execution. For example, if a salesperson sells more than 500 items this month, give the salesperson a bonus. Also, if a student’s grade on an algebra test is greater than 85 percent, congratulate the student for doing well; otherwise, recommend that the student study harder for the next test.

Java supports the if, if-else, and switch decision statements. Additionally, a new switch expressions feature has been added to Java 12.

The if statement

The simplest of Java’s decision statements is the if statement, which evaluates a Boolean expression and executes another statement when this expression evaluates to true. The if statement has the following syntax:

if (Boolean expression)
   statement

The if statement starts with reserved word if and continues with a parenthesized Boolean expression, which is followed by the statement to execute when the Boolean expression evaluates to true.

The following example demonstrates the if statement. When the age variable contains a value of 55 or greater, if executes System.out.println(...); to output the message:

if (age >= 55)
   System.out.println("You are or were eligible for early retirement.");

Many people prefer to wrap any simple statement that follows the if statement in braces, effectively converting it to an equivalent compound statement:

if (age >= 55)
{
   System.out.println("You are or were eligible for early retirement.");
}

Although the braces clarify what is being executed by the if statement, I believe that the indentation provides this clarity, and that the braces are unnecessary.

Experimenting with if statements

Let’s try out this example usingjshell. Restart jshell and then introduce an age variable (of type int) that’s initialized to 55:

jshell> int age = 55

Next, enter the first example if statement (without the curly braces surrounding its body):

jshell> if (age >= 55)
   ...>    System.out.println("You are or were eligible for early retirement.");

You are or were eligible for early retirement.

jshell>

Notice that the jshell> prompt changes to the ...> continuation prompt when you enter a multiline snippet. Pressing Enter after the last snippet line causes jshell to immediately execute the snippet.

Execute /list to list all snippets. I observe that the if statement snippet has been assigned 2 in my session. Executing /2 causes jshell to list and then execute this snippet, and the same message is output.

Now, suppose you assign 25 to age and then re-execute /2 (or the equivalent snippet number in your session). This time, you should not observe the message in the output.

The if-else statement

The if-else statement evaluates a Boolean expression and executes a statement. The statement executed depends on whether the expression evaluates to true or false. Here’s the syntax for the if-else statement:

if (Boolean expression)
   statement1
else
   statement2

The if-else statement is similar to the if statement, but it includes the reserved word else, followed by a statement to execute when the Boolean expression is false.

The following example demonstrates an if-else statement that tells someone who is less than 55 years old how many years are left until early retirement:

if (age >= 55)
   System.out.println("You are or were eligible for early retirement.");
else
   System.out.println("You have " + (55 - age) + " years to go until early retirement.");

Chaining if-else statements

Java lets you chain multiple if-else statements together for situations where you need to choose one of multiple statements to execute:

if (Boolean expression1)
   statement1
else
if (Boolean expression2)
   statement2
else
   ...
else
   statementN

Chaining works by executing a subsequent if-else statement whenever the current if statement’s Boolean expression evaluates to false. Consider a demonstration:

if (temperature < 0.0)
   System.out.println("freezing");
else
if (temperature > 100.0)
   System.out.println("boiling");
else
   System.out.println("normal");

The first if-else statement determines if temperature‘s value is negative. If so, it executes System.out.println("freezing");. If not, it executes a second if-else statement.

The second if-else statement determines if temperature‘s value is greater than 100. If so, it executes System.out.println("boiling");. Otherwise, it executes System.out.println("normal");.

The dangling-else problem

When if and if-else are used together, and the source code isn’t properly indented, it can be difficult to determine which if associates with the else. You can see the problem in the code below:

int x = 0;
int y = 2;
if (x > 0)
   if (y > 0)
      System.out.println("x > 0 and y > 0");
else
   System.out.println("x <= 0");

You would probably expect to see x <= 0 as the output from this code, but it will never happen; instead, nothing will output. The problem is that the else matches up to its nearest if, which is if (y > 0). Reformatting the code makes it clearer what is happening:

int x = 0;
int y = 2;
if (x > 0)
   if (y > 0)
      System.out.println("x > 0 and y > 0");
   else
      System.out.println("x <= 0");

Here it’s clearer than an if (y > 0) ... else ... if-else statement follows the if (x > 0) statement. To match the intent of the previous example, you need to introduce brace characters around if (y > 0) and its subsequent statement. Essentially, a block will follow if (x > 0):

int x = 0;
int y = 2;
if (x > 0)
{
   if (y > 0)
      System.out.println("x > 0 and y > 0");
}
else
   System.out.println("x <= 0");

Because x > 0 evaluates to false, System.out.println("x <= 0"); executes. The else reserved word clearly matches up to if (x > 0).

The switch statement

When you need to choose between several execution paths, the switch statement offers a more efficient alternative to chaining. Have a look at the switch statement:

switch (selector expression)
{
   case value1: statement1 [break;]
   case value2: statement2 [break;]
   ...
   case valueN: statementN [break;]
   [default: statement]
}

The switch statement begins with reserved word switch and continues with a selector expression that selects one of the subsequent cases or the default case to execute. The selector expression evaluates to an integer, a character, or a string.

Each case identifies a statement to execute. The case begins with the reserved word case and a value that labels the case. Following a colon (:) character is the statement to execute. The statement can be optionally followed by break;, to transfer execution to the first statement after switch. If none of the case labels matches the selector expression’s value, the optional default case, which begins with reserved word default, will execute.

Below is a switch statement used to determine if an integer value is even or odd (by using the remainder operator). It then outputs an appropriate message via the case whose label matches the remainder:

int i = 27;
switch (i % 2)
{
   case 0: System.out.println("even");
           break;

   case 1: System.out.println("odd");
}

In this case, the output would be odd because i % 2 yields 1, which matches the second case label. If we omitted break;, and if the number was even, the output would be even followed by odd, because execution would drop through to the second case.

Switching case

Sometimes, it’s desirable to have execution drop through to the next case. For example, suppose you wanted to execute common code in response to the user specifying an uppercase or lowercase command-line option letter:

switch (args[i])
{
   case "-v":
   case "-V": System.out.println("Version 1.0");
              break;

   // ...

   default  : System.out.println("unknown option");
}

Imagine that a for statement (discussed shortly) is iterating over each of the arguments in the array of command-line arguments passed to an application’s main() method. If the argument is -v (dash and lowercase v) or -V (dash and uppercase V), the application’s version number is output. When -v is specified, it’s necessary to have execution drop through to the following case, which outputs the version number when -V is specified.

The default case is executed whenever the string referenced by args[i] doesn’t match any of the case labels. In other words, the user has specified an unknown option.

Switch expressions in Java 12

Java SE 12 introduced switch expressions as an enhancement to the switch statement. Think of a switch expression as a kind of multiway conditional operator (?:). Switch expressions are intended to simplify coding and to prepare for pattern matching in Java.

The switch expressions feature is currently available as a preview language feature, so that developers can try it out and offer feedback. As of this writing, you need a special command-line option to access it. Since there’s no guarantee that switch expressions will remain in future version of Java, I’ll just present a simple example using jshell.

Start jshell with the --enable-preview option, as follows:

jshell --enable-preview

At the jshell> prompt, enter the following enumerated type (you’ll learn about enumerated types later in this series):

jshell> enum Coin { PENNY, NICKEL, DIME, QUARTER }
|  created enum Coin

Continue by entering the following snippet at the jshell> prompt:

jshell> var coin = Coin.DIME
coin ==> DIME

jshell> var value = switch(coin) {
   ...> case PENNY -> 1;
   ...> case NICKEL -> 5;
   ...> case DIME -> 10;
   ...> case QUARTER -> 25;
   ...> }
value ==> 10

jshell>

In this example, we first introduce the coin variable initialized to Coin‘s DIME value. We then introduce a value variable that receives its value from a switch expression. This expression switches on coin and offers four cases. Each case returns the numeric value of the coin (e.g., 1 for PENNY). The semicolon terminator is required for each case. After entering the switch expression, jshell evaluates it and outputs the value (10) assigned to value.

See Dustin Marx’s “JDK 12: Switch Statements/Expressions in Action” for more about switch expressions in Java 12.

Iterating and looping: for, while, and do-while

Iteration statements (also known as loop statements) repeatedly execute other statements for a specific number of iterations (loops) or indefinitely until some terminating condition arises. For example, as previously mentioned, you might want to iterate over all of the String objects in the array of command-line arguments passed to a main() method. Java supports the for, while, and do-while iteration statements.

The for statement and for loops in Java

The for statement executes another statement a specific number of times or indefinitely. It is essentially a compact form of the while statement (discussed later) and has the following syntax:

for ([initialize]; [test]; [update])
   statement

This example shows that a for statement begins with the reserved word for and continues with a parentheses-delimited and semicolon-separated sequence of three sections:

  • initialize: A comma-separated list of variable declarations or assignments. These variables, which are known as iteration variables or loop variables, are used to index arrays, take part in calculations, or perform other tasks.
  • test: A Boolean expression that determines how long the loop executes. Execution continues for as long as this expression remains true.
  • update: A comma-separated list of expressions that typically modify the loop variables.

Following the for statement is a statement to execute repeatedly.

Each of the three sections is optional. As a result, for can be shrunk down to for (; ;). Because there is no stopping condition, the resulting loop is known as an infinite loop.

The following example uses the for statement to iterate over all elements in an array named args, outputting the value of each array element:

for (int i = 0; i < args.length; i++)
   System.out.println(args[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.

Variable i is visible to the for statement’s test and update sections, and to statement. However, it isn’t visible to subsequent statements. If you want subsequent statements to see i‘s final value, declare i before for, as follows:

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

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.

Here’s an example of 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, we change the postincrement statement to an expression that’s passed to the array index operator. Although the code is more compact, some 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 the 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 and raise an out-of-bounds exception. In contrast, you would access the array at least once with do-while. 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 and continuing: break and continue

You’ve seen the break statement used to break out of a switch statement after a case has executed. We can also use break statements as part of an iteration statement, along with continue statement. We’ll explore both of these options.

Unlabeled 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. Here it is by itself:

break;

Here’s an 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;
}

Here we’ve introduced 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.

Empty statements

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 rn characters, one call is needed on UnixLinux 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.

Example application: Exploring statements

Now that you’ve learned about Java’s fundamental language features, you have everything you need start writing interesting Java applications. As an example, I’ve written a game that randomly selects an integer ranging from 0 through 9 and asks you to guess the number. If you guess too high or too low, the game will tell you. It will also tell you when you guess correctly, and it will ask you if you want to play again.

Before I show you the application’s source code, I need to introduce several classes and methods you’ll see in the code:

  • 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 for the Guess application.

Listing 1. Example application for guessing in Java (Guess.java)

class Guess
{
   public static void main(String[] args) throws Exception
   {
      outer:
      while (true)
      {
         System.out.println("I'm thinking of a number between 0 and 9.");
         int number = (int) (Math.random() * 10);
         while (true)
         {
            int guessNumber;
            while (true)
            {
               System.out.println("Enter your guess number between 0 and 9.");
               guessNumber = System.in.read();
               while (System.in.read() != 'n');
               if (guessNumber >= '0' && guessNumber <= '9')
               {
                  guessNumber -= '0';
                  break;
               }
            }
            if (guessNumber < number)
               System.out.println("Your guess is too low.");
            else
            if (guessNumber > number)
               System.out.println("Your guess is too high.");
            else
            {
               System.out.println("Congratulations! You guessed correctly.");
               while (true)
               {
                  System.out.println("Press n for new game or q to quit.");
                  int ch = System.in.read();
                  while (System.in.read() != 'n');
                  if (ch == 'n')
                     continue outer;
                  if (ch == 'q')
                     break outer;
               }
            }
         }
      }
   }
}

Guess demonstrates many of the fundamental Java language features presented in the previous four tutorials. The main() method presents a while statement that generates a new number and gives you a chance to guess it. The expression (int) (Math.random() * 10) multiplies random()‘s return value by 10 to change the range to 0.0 to almost 10.0, and converts the result to an integer ranging from 0 through 9.

After generating the number, main() executes an inner while statement to handle the guesswork. It repeatedly prompts for a guess, converts the pressed key’s Unicode character value to a binary integer value from 0 through 9, and determines whether the user has guessed correctly or not. A suitable message is output. Users who guess correctly are given the chance to play a new game by pressing n, or to quit the application by pressing q.

An interesting part of the source code is while (System.in.read() != 'n');. I use this statement to flush the line separator character(s) (e.g., rn on Windows) from the operating system’s keyboard buffer. Without this, you would see multiple prompts because each separator character will be interpreted as an attempt to enter a value from 0 through 9 (or n or q). If you’re running Java on an older version of Mac OS, you’ll probably have to replace n with r, which is the Mac’s line separator. No changes are necessary when running on Linux or Unix, whose line separator is n.

Compile Listing 1 as follows:

javac Guess.java

Then run the application:

java Guess

Below is the output from a sample run:

I'm thinking of a number between 0 and 9.
Enter your guess number between 0 and 9.
5
Your guess is too high.
Enter your guess number between 0 and 9.
2
Your guess is too low.
Enter your guess number between 0 and 9.
3
Your guess is too low.
Enter your guess number between 0 and 9.
4
Congratulations! You guessed correctly.
Press n for new game or q to quit.
q

Note that you could make this code portable by working with the standard class library’s System class, which offers access to the line.separator property. This task could be good for a future exercise, when you’re more comfortable with Java’s classes and methods.

Using the Java Shell editor

You might want to create or edit this application using the jshell utility. You’ll find the /edit command helpful for this purpose. When you enter /edit, jshell displays an edit window with Cancel, Accept, and Edit buttons:

  • Cancel: Cancel the editor without saving changes.
  • Accept: Save changes without leaving the editor. Java Shell displays a modification message at the prompt when changes are saved.
  • Exit: Save changes and leave the editor. Java shell displays a modification message at the prompt when changes are saved.

Copy Listing 1 into and exit the editor. Then enter Guess.main(null) at the jshell> prompt to run the application. When you finish with the application, enter q and you’ll be returned to the jshell> prompt.

Conclusion

Over the past four tutorials, you’ve learned all about Java’s fundamental language features, including expressions, operators, and statements, which are the workhorses of a Java application. Mastering these basic language features gives you a solid foundation for exploring more advanced language features. We’ll begin this expansion in the next Java 101 tutorial, which introduces Java classes and objects.