Main Page

Previous Next

Making Decisions

Making choices will be a fundamental element in all your programs. You need to be able to make decisions like, "If the bank balance is large, buy the car with the go-faster stripes, else renew the monthly bus ticket". In programming terms this requires the ability to make comparisons between variables, constants, and the values of expressions, then executing one group of statements or another, depending on the result of a given comparison. The first step to making decisions in a program is to look at how we make comparisons.

Making Comparisons

Java provides you with six relational operators for comparing two data values. Either of the data values you are comparing can be variables, constants or expressions drawn from Java's primitive data types – byte, short, int, long, char, float or double.

Relational Operators

Description

>

Produces the value true if the left operand is greater than the right operand, and false otherwise.

>=

Produces the value true if the left operand is greater than or equal to the right operand, and false otherwise.

==

Produces the value true if the left operand is equal to the right operand, and false otherwise.

!=

Produces the value true if the left operand is not equal to the right operand, and false otherwise.

<=

Produces the value true if the left operand is less than or equal to the right operand, and false otherwise.

<

Produces the value true if the left operand is less than the right operand, and false otherwise.

As you see, each operator produces either the value true, or the value false, and so is eminently suited to the business of making decisions.

If you wish to store the result of a comparison, you use a boolean variable. We saw how to declare these in the previous chapter. For example you can define a boolean variable state and you can set its value in an assignment as follows:

boolean state = false;
state = x - y < a + b;

The value of the variable state will be set to true in the assignment if x-y is less than a+b, and to false otherwise.

To understand how the expression above is evaluated, take a look back at the precedence table for operators that we introduced in the last chapter. You will see that the comparison operators are all of lower precedence than the arithmetic operators, so arithmetic operations will always be completed before any comparisons are made, unless of course there are parentheses saying otherwise. The expression,

x - y == a + b

will produce the result true if x-y is equal to a+b, since these arithmetic sub-expressions will be evaluated first, and the values that result will be the operands for the == operator. Of course, it is helpful to put the parentheses in, even though they are not strictly necessary. It leaves no doubt as to what is happening if you write:

(x – y) == (a + b)

Note that if the left and right operands of a relational operator are of differing types, values will be promoted in the same way as we saw in the last chapter for mixed arithmetic expressions. So if aDouble is of type double, and number is of type int, in the following expression:

aDouble < number + 1

the value produced by number + 1 will be calculated as type int, and this value will be promoted to type double before comparing it with the value of aDouble.

The if Statement

The first statement we will look at that can make use of the result of a comparison is the if statement. The if statement, in its simplest configuration, is of the form:

if(expression)
statement;

where expression can be any expression that produces a value true or false. You can see a graphical representation of this logic in the following diagram:

If the value of expression is true, the statement that follows the if is executed, otherwise it isn't. A practical example of this is as follows:

if(number%2 != 0)            // Test if number is odd
  ++number;                  // If so make it even

The if tests whether the value of number is odd by comparing the remainder, after dividing by 2, with 0. If the remainder isn't equal to 0, the value of number is odd, so we add 1 to make it even. If the value of number is even, the statement incrementing number will not be executed.

Important 

Note how the statement is indented. This is to show that it is subject to the if condition. You should always indent statements in your Java programs as cues to the program structure. We will gather more guidelines on the use of statement indenting as we work with more complicated examples.

You may sometimes see a simple if written on a single line. The previous example could have been written:

if(number%2 != 0) ++number;  // If number is odd, make it even

This is perfectly legal. The compiler ignores excess spaces and newline characters – the semi-colon acts as the delimiter for a statement. Writing an if in this way saves a little space, and occasionally it can be an aid to clarity, when you have a succession of such comparisons for instance, but generally it is better to write the action statement on a separate line to the condition being tested.

Statement Blocks

In general, wherever you can have one executable statement in Java, you can replace it with a block of statements enclosed between braces instead. So a statement block between braces can also be nested in another statement block to any depth. This means that we can use a statement block within the basic if statement that we just saw. The if statement can equally well be of the form:

if(expression) {
  statement 1;
  statement 2;
  ...
  statement n;
}

Now if the value of expression is true, all the statements enclosed in the following block will be executed. Of course, without the braces to enclose the block, the code no longer has a statement block:

if(expression)
  statement 1;
  statement 2;
  ...
  statement n;

Here, only the first statement, statement 1, will be omitted when the if expression is false; the remaining statements will always be executed regardless of the value of expression. You can see from this that indenting is just a visual cue to the logic. It has no effect on how the program code executes. This looks as though the sequence of statements belongs to the if, but only the first one does because there are no braces. The indenting is incorrect here.

Important 

In this book, we will adopt the convention of having the opening brace on the same line as the statement. The closing brace will then be aligned with the statement. We will indent all the statements within the block from the braces so that they are easily identified as belonging to the block. There are other conventions that you can use if you prefer, the most important consideration being that you are consistent.

As a practical example of an if statement that includes a statement block, we could write:

if(number%2 != 0) {        // Test if number is odd
  // If so make it even and output a message
  ++number;
  System.out.println("Number was forced to be even and is now " + number);
}

Now both statements between the braces are executed if the if expression is true, and neither of them is executed if the if expression is false.

Note 

It is a good practice to always have opening and closing braces even when there is only a single action statement, this helps clarify the code and will stop confusion of its logic.

Statement blocks are more than just a convenient way of grouping statements together – they affect the life and accessibility of variables. We will learn more about statement blocks when we discuss variable scope later in this chapter. In the meantime let's look a little deeper into what we can do with the if statement.

The else Clause

We can extend the basic if statement by adding an else clause. This provides a second choice of statement, or statement block, that is executed when the expression in the if statement is false. You can see the syntax of this clause, and how the program's control flow works, in this diagram:

Click To expand

This provides an explicit choice between two courses of action – one for when the if expression is true and another for when it is false.

We can apply this in a console program and try out the random() method from the Math class at the same time.

Try It Out – if-else

When you have entered the program text, save it in a file called NumberCheck.java. Compile it and then run it a few times to see what results you get.

public class NumberCheck {
  public static void main(String[] args) {
    int number = 0;
    number = 1+(int)(100*Math.random());  // Get a random integer between 1 & 100
    if(number%2 == 0) {                   // Test if it is even
      System.out.println("You have got an even number, " + number); // It is even

    } else {
      System.out.println("You have got an odd number, " + number);  // It is odd
    }
  }
}

How It Works

We saw the method random() in the standard class Math in the previous chapter. It returns a random value of type double between 0.0 and 1.0, but the result is always less than 1.0, so the largest number you will get is 0.9999... (with the number of recurring digits being limited to the maximum number that the type double will allow, of course). Consequently, when we multiply the value returned by 100.0 and convert this value to type int with the explicit cast, we discard any fractional part of the number and produce a random integer between 0 and 99. Adding 1 to this will result in a random integer between 1 and 100, which we store in the variable number. We then generate the program output in the if statement. If the value of number is even, the first println() call is executed, otherwise the second println()call in the else clause is executed.

Note the use of indentation here. It is evident that main() is within the class definition, and the code for main() is clearly distinguished. You can also see immediately which statement is executed when the if expression is true, and which applies when it is false.

Nested if Statements

The statement that is executed when an if expression is true can be another if, as can the statement in an else clause. This will enable you to express such convoluted logic as "if my bank balance is healthy then I will buy the car if I have my check book with me, else I will buy the car if I can get a loan from the bank". An if statement that is nested inside another can also itself contain a nested if. You can continue nesting ifs one inside the other like this for as long as you still know what you are doing – or even beyond if you enjoy confusion.

To illustrate the nested if statement, we can modify the if from the previous example:

if(number%2 == 0) {                 // Test if it is even
  if(number < 50) {                 // Output a message if number is < 50
    System.out.println("You have got an even number < 50, " + number);
  }

} else {
  System.out.println("You have got an odd number, " + number); // It is odd
}

Now the message for an even value is only displayed if the value of number is also less than 50.

The braces around the nested if are necessary here because of the else clause. The braces constrain the nested if in the sense that if it had an else clause, it would have to appear between the braces enclosing the nested if. If the braces were not there, the program would still compile and run but the logic would be different. Let's see how.

With nested ifs, the question of to which if statement a particular else clause belongs often arises. If we remove the braces from the code above, we have:

if(number%2 == 0)                   // Test if it is even
  if(number < 50 )                  // Output a message if number is < 50
    System.out.println("You have got an even number < 50, " + number);
else
  System.out.println("You have got an odd number, " + number); // It is odd

This has substantially changed the logic from what we had before. The else clause now belongs to the nested if that tests whether number is less than 50, so the second println()call is only executed for even numbers that are greater than or equal to 50. This is clearly not what we wanted since it makes nonsense of the output in this case, but it does illustrate the rule for connecting elses to ifs, which is:

Important 

An else always belongs to the nearest preceding if that is not in a separate block, and is not already spoken for by another else.

You need to take care that the indenting of statements with nested ifs is correct. It is easy to convince yourself that the logic is as indicated by the indentation, even when this is completely wrong.

Let's try the if-else combination in another program:

Try It Out – Deciphering Characters the Hard Way

Create the class LetterCheck, and code its main() method as follows:

public class LetterCheck {
  public static void main(String[] args) {
    char symbol = 'A';
    symbol = (char)(128.0*Math.random());        // Generate a random character

    if(symbol >= 'A') {                           // Is it A or greater?
      if(symbol <= 'Z') {                        // yes, and is it Z or less?
        // Then it is a capital letter
        System.out.println("You have the capital letter " + symbol);
 
     } else {                                     // It is not Z or less
        if(symbol >= 'a') {                     // So is it a or greater?
          if(symbol <= 'z') {                  // Yes, so is it z or less?
            // Then it is a small letter
            System.out.println("You have the small letter " + symbol);

          } else {                               // It is not less than z
            System.out.println(
            "The code is greater than a but it's not a letter");
          }
 
       } else {
          System.out.println(
                      "The code is less than a and it's not a letter");
        }
      }

    } else {
      System.out.println("The code is less than A so it's not a letter");
    }
  }
}

How It Works

This program figures out whether the character stored in the variable symbol is an uppercase letter, a lowercase letter, or some other character. The program first generates a random character with a numeric code between 0 and 127, which corresponds to the characters in the basic 7-bit ASCII (ISO 646) character set. The Unicode coding for the ASCII characters is numerically the same as the ASCII code values. Within this character set, the letters 'A' to 'Z' are represented by a contiguous group of ASCII codes with decimal values from 65 to 90. The lowercase letters are represented by another contiguous group with ASCII code values that have decimal values from 97 to 122. So to convert any capital letter to a lowercase letter, you just need to add 32 to the character code.

The if statements are a bit convoluted so let's look at a diagram of the logic.

Click To expand

We have four if statements altogether. The first if tests whether symbol is 'A' or greater. If it is, it could be a capital letter, a small letter, or possibly something else. But if it isn't, it is not a letter at all, so the else for this if statement (towards the end of the program) produces a message to that effect.

The nested if statement, which is executed if symbol is 'A' or greater, tests whether it is 'Z' or less. If it is, then symbol definitely contains a capital letter and the appropriate message is displayed. If it isn't then it may be a small letter, so another if statement is nested within the else clause of the first nested if, to test for this possibility.

The if statement in the else clause tests for symbol being greater than 'a'. If it isn't, we know that symbol is not a letter and a message is displayed. If it is, another if checks whether symbol is 'z' or less. If it is we have a small letter, and if not we don't have a letter at all.

You will have to run the example a few times to get all the possible messages to come up. They all will – eventually.

Having carefully crafted our convoluted and cumbersome condition checking, now's the time to reveal that there is a much easier way to achieve the same result.

Previous Next
JavaScript Editor Java Tutorials Free JavaScript Editor