Espresso: A Concentrated Introduction to Java
Summary: We consider Java's conditional operations, which permit programs to choose between different sequences of operations.
Prerequisites: Java basics. Numeric types.
Contents:
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.
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 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.
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 }
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).
The simplest Boolean expressions are numeric comparisons.
You can compare two primitive numeric values, x
and
y
, with one of the following.
x < y
(less than)
x <= y
(less than or equal to)
x == y
(equal to; note there are two
equals signs)
x != y
(not equal to)
x >= y
(greater than or equal to)
x > y
(greater than)
Note that these are primitive operations, rather than methods, so they do not use the traditional object.method syntax.
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)) { ... }
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
obj
naturally precedes
other
obj
is naturally equal to
other
obj
naturally follows
other
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).
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
;
;
Check with Bobby