Espresso: A Concentrated Introduction to Java


Making Choices: Conditionals in Java

Summary: We consider Java's conditional operations, which permit programs to choose between different sequences of operations.

Prerequisites: Java basics. Numeric types.

Contents:

About Control Structures

As you may have observed, the programs we have written to date are necessarily fairly simple. Each program simply executes a sequence of operations (including requesting objects to execute operations) and then stops. As you might guess, it is difficult to write significant programs with this limited set of control.

Hence, most programming languages provide a variety of control structures that let you affect the sequence of operations that are executed, depending on various conditions. For example, your program might behave significantly differently for different inputs (e.g., if a user enters a correct or incorrect password) or it might repeat certain commands.

Most imperative programming languages include three kinds of control structures: conditional, loops, and subroutines (methods). You have already learned how to call methods, and you will soon learn to write your own. In this reading, we will consider conditionals.

Conditional Basics

Conditionals let you choose between a variety of statements (or sequences of statements), using one or more conditions to help you choose. Different languages provide very different forms of conditionals, so one of the first things you must consider when learning a new language is what forms of conditionals it provides. Java provides two forms of conditionals, if statements and case statements. In this reading, we will focus primarily on if statements.

Conditionals are a common structure in recipes. For example, you might read for fluffier pancakes, decrease the milk by 10% or if above 5000 ft, decrease the oven temperature by 25 degrees F.

If Statements

If statements are perhaps the simplest form of conditional. An if statement lets you choose between two options.

In Java, the basic form of an if statement is

if (test) {
  statements-to-execute-if-test-succeeds;
} // if
else {
  statements-to-execute-if-test-fails;
}

Upon seeing this structure, Java first runs the test. Java then executes the statements-to-execute-if-test-succeeds only when the test holds. if the test fails to hold, Java executes the statements-to-execute-if-test-fails.

In Java, we might set n to the larger of a and b with

if (a > b) {
  n = a;
}
else {
  n = b;
}

Note that the test must return a boolean (truth) value, which we discuss in a subsequent section. Note also that the test must be surrounded by parentheses.

As the italicized parts above suggest, you can put multiple statements in each branch of the if. For example, if a user enters an incorrect value, we might want to print a complaint and then use a default value.

if (helper.isValid(userInput)) {
  pen.println("Thanks for entering " + userInput); }
else {
  pen.println("I'm sorry, '" + userInput + "' is invalid.");
  pen.println("Using '" + default + "' instead.");
  userInput = default;
}

There are a few variants of the if statement. If you do not want to do anything special if the test fails, you can leave off the else and everything after it.

if (test) {
  statements-to-execute-if-test-succeeds;
} // if

In this case, if the test fails, Java simply moves on to the next statement, skipping the statements to execute.

The braces are also optional if you have only a single statement rather than a sequence of statements. However, experience suggests that it's generally better to use them anyway, because your code may eventually grow from one statement to a sequence.

Nesting If Statements

Some programming languages provide a structure in which you provide a sequence of statement blocks with associated conditions (sometimes called guards). The program then either tests the conditions in order and executes the statement block for the first true condition (a deterministic version), or chooses some true condition and executes the corresponding statement block (a nondeterministic version).

Unfortunately, Java provides no additional control structure for this kind of condition. Most Java programmers simulate the control structure with a sequence of nested conditionals.

if (test1) {
  stuff1
}
else if (test2) {
  stuff2
}
else if (test3) {
  stuff3
}
else if (testn) {
  stuffn
}
else {
  default-stuff
}

Boolean Values

As you may have noted, conditionals require tests (conditions). In Java, these tests must be expressions that compute They must be boolean values. boolean is a primitive type, like int or double. Booleans are truth values: they are either true or false (and, if you desire, you can even express those truth values with those terms).

Numeric Comparison

The simplest Boolean expressions are numeric comparisons. You can compare two primitive numeric values, x and y, with one of the following.

Note that these are primitive operations, rather than methods, so they do not use the traditional object.method syntax.

Boolean Operations

Given two Boolean expressions, it is possible to combine those expressions with one of the three kinds of Boolean operators: and, or, and not. We can compute the and of two Boolean expressions with b1 && b2. We can compute the or of two Boolean expressions with b1 || b2. We can negate a Boolean expression with !b. These operations are defined by the following truth table

b1 b2 b1 && b2 b1 || b2 !b1
false false false false true
false true false true
true false false true false
true true true true

We can combine these operations in a variety of ways. For example, if we wanted to determine whether an integer, i is between 1 and 10, inclusive, we might write

if ((i >= 1) && (i <=10)) {
  ...
}

Comparing Objects

You know how to compare values of primitive types and to combine Boolean expressions for more complex comparisons. What should you do if you want to analyze objects? You can begin with two comparison methods, equals and compareTo.

You can typically compare any two objects with the equals method, which does need to be defined for most classes. The test a.equals(b) method returns true if a and b are naturally equal and false otherwise. Each class may define its own sense of natural equality.

For example, to determine if an operator (represented as a string) that you've just read is an asterisk, you might write

if (operator.equals("*")) {
  pen.println(x*y);
}

At times, you will find that variables do not yet refer to any particular objects. In that case, we say the variables are null and write

if (myvar == null) {
  ...
}

You can also compare many objects with the compareTo method, which you call as obj.compareTo(other). Such a call returns

For example, to determine whether a BigDecimal, d, is between 0 and 1 (inclusive), we might write

if ((d.compareTo(BigDecimal.ZERO) >= 0) && (d.compareTo(BigDecimal.ONE) <= 0) {
  ...
}

The compareTo method is supposed to be transitive and reflexive. By transitive, we mean that if a naturally precedes b and b naturally precedes c, then a must naturally precede c. By reflexive, we mean that if a naturally precedes b, then b must naturally follow a (and vice versa).

History

Tuesday, 27 September 2005 [Samuel A. Rebelsky]

Thursday, 9 February 2006 [Samuel A. Rebelsky]

Monday, 1 October 2007 [Samuel A. Rebelsky]


This page was generated by Siteweaver on Mon Oct 1 07:19:03 2007.
The source to the page was last modified on Mon Oct 1 07:18:39 2007.
This page may be found at http://www.cs.grinnell.edu/~rebelsky/Espresso/Readings/conditionals.html.

You may wish to validate this page's HTML ; Valid CSS! ; Check with Bobby

Samuel A. Rebelsky
rebelsky@grinnell.edu