An Introduction to
Programming and Object
Oriented Design using Java
2nd Edition. May 2004
Jaime Niño
Frederick Hosch
Chapter 4 : Conditionals
Objectives
After studying this chapter you should understand the
following:
the notions of preconditions, postconditions, and invariants;
the purpose of a conditional statement;
the function of boolean expressions;
the purpose of a compound statement.
Also, you should be able to:
write and evaluate boolean expressions;
write conditional statements of various forms;
implementation methods that use conditional statements;
implement a class tester which automatically verifies test results.
May 2004
NH-Chapter4
1
Postconditions and invariants
Method currentCount in Counter is specified as
/**
* The number of items counted.
*/
public int currentCount () { …
Specification stipulates invoking method returns a
value of type int.
May 2004
NH-Chapter4
2
Postconditions and invariants
Can be more precise in specifying result : integer result is nonnegative.
/**
* The number of items counted.
*
* @ensure this.currentCount() >= 0
*/
public int currentCount () { …
Postcondition: condition that implementor promises will be
satisfied when method completes execution.
Implementor must make sure that the method satisfies the
postcondition.
May 2004
NH-Chapter4
3
Postconditions and invariants
Need to make sure instance variable used to store
current count will never contain a negative value.
Document this via a class invariant:
private int count;
// current count
// invariant: count >= 0
A class invariant will always be true of all instances of the
class.
May 2004
NH-Chapter4
4
Postconditions and invariants
If we add decrementCount to Counter:
public void decrementCount ()
Decrement positive count by 1; zero count remains zero.
In implementation, need to add guard to be sure not
to decrement when count == 0
May 2004
NH-Chapter4
5
The if-then statement
if (condition)
statement
B E G IN
true
condition
false
statement
E N D
May 2004
NH-Chapter4
6
Implemeting decrementCount
/**
* Decrement positive count by 1;
* zero count remains zero
*/
public void decrementCount () {
if (count > 0)
count = count - 1;
}
May 2004
NH-Chapter4
7
Explorer: invariants and guards
Restrict Explorer’s tolerance to be a non-negative integer.
private int tolerance;
// current tolerance
// invariant: tolerance >= 0
/**
* Damage (hit points) required to defeat
* this Explorer.
*
* @ensure tolerance >= 0
*/
public int tolerance () {
return tolerance;
}
Need to insure value assigned in each case is not negative.
May 2004
NH-Chapter4
8
Explorer: invariants and guards
Consider method takeThat.
Need to guard the two statements:
if (hitStrength <= tolerance)
tolerance = tolerance - hitStrength;
if (hitStrength > tolerance)
tolerance = 0;
But, only one of those should execute when invoking takeThat.
May 2004
NH-Chapter4
9
if-then-else statement
if (condition)
statement1
else
statement2
B E G IN
true
false
condition
statement
statement
2
1
E N D
May 2004
NH-Chapter4
10
Implementing method takeThat
public void takeThat (int hitStrength) {
if (hitStrength <= tolerance)
tolerance = tolerance - hitStrength;
else
tolerance = 0;
}
May 2004
NH-Chapter4
11
Implementing constructor
public Explorer (String name, Room location,
int strength, int tolerance) {
…
if (tolerance >= 0)
this.tolerance = tolerance;
else
this.tolerance = 0;
…
}
May 2004
NH-Chapter4
12
Compound statements
if (condition) {
statement1
…
statementN
}
if (condition) {
statement11
…
statement1N
} else {
statement21
…
statement2M
}
May 2004
NH-Chapter4
13
Conditions: boolean expressions
Boolean expressions:
Produce boolean values when evaluated;
Evaluate to true or false.
Can declare boolean variables, and assign values:
private boolean tooBig;
And can assign values to it:
tooBig = true;
Or
tooBig = size > 10;
May 2004
NH-Chapter4
14
Handling multiple cases
A conditional statement divides problem into two
cases to be considered independently.
In many problems, there are more than two cases, or
cases need to be further divided into subcases.
Use nesting conditional statements.
May 2004
NH-Chapter4
15
Handling multiple cases
Assume class Date with properties day, month,year.
Implement a Date’s query that will tell whether or
not a date occurs in a leap year.
public boolean isLeapYear ()
This Date occurs in a leap year.
May 2004
NH-Chapter4
16
Handling multiple cases
isLeapYear
Case: year divisible by 4
???
Case: year not divisible by 4
not a leap year.
Case: divisible by 100 Case: not divisible by
100
???
is leap
Case: divisible Case: not divisible
by 400
by 400
is leap
is not leap
May 2004
NH-Chapter4
17
Handling multiple cases
// This Date occurs in a leap year.
public boolean isLeapYear () {
boolean aLeapYear;
if (year % 4 == 0)
if (year % 100 == 0)
// if divisible by 100,
// must also be divisible by 400
aLeapYear = (year % 400 == 0);
else // divisible by 4, not by 100
aLeapYear = true;
else // not divisible by 4
aLeapYear = false;
return aLeapYear;
}
May 2004
NH-Chapter4
18
Cascading conditionals
When problem splits into more than two cases:
“cascade” if-then-else statements.
if (case1)
handleCase1
else if (case2)
handleCase2
…
else if (penultimateCase)
handlePenultimateCase
else
handleLastCase
May 2004
NH-Chapter4
19
TrafficLight’s change() method
change
:
case: light is GREEN
change to YELLOW
May 2004
case: light is YELLOW
change to RED
NH-Chapter4
case: light is RED
change to GREEN
20
TrafficLight’s change() method
public void change () {
if (light == GREEN)
light = YELLOW;
else if (light == YELLOW)
light = RED;
else // light == RED
light = GREEN;
}
May 2004
NH-Chapter4
21
Dangling else
There is an ambiguity as to whether the structure
if (condition1)
if (condition2)
statement1
else
statement2
Is it an if-then nested in an if-then-else, or an
if-then-else nested in an if-then?
May 2004
NH-Chapter4
22
Dangling else
B E GIN
false
condition1
B E GI N
true
condition1
true
false
condition2
statement2
true
false
statement1
statement2
condition2
true
statement1
false
E ND
May 2004
E ND
NH-Chapter4
23
Dangling else: equivalent statements
if (condition1)
if (condition2)
statement1
else
statement2
May 2004
if (condition1) {
if (condition2)
statement1
else
statement2
}
NH-Chapter4
24
Example: combination lock
Responsibilities:
Know:
The combination
whether unlocked or locked
Do:
lock
unlock
May 2004
NH-Chapter4
25
CombinationLock class
Class: CombinationLock
Queries:
is open
Commands:
lock
unlock
May 2004
NH-Chapter4
26
Class CombinationLock specifications
public class CombinationLock
Contructor:
public CombinationLock (int combination)
Queries:
public boolean isOpen()
Commands:
public void close ()
public void open(int combination)
May 2004
NH-Chapter4
27
Class CombinationLock
implementation
Component variables:
private int combination;
private boolean isOpen;
May 2004
NH-Chapter4
28
Structure for a simple test
public class CombinationLock {
private int combination;
private boolean isOpen;
public CombinationLock (int combination) {
}
public boolean isOpen () {
return true;
}
public void close () {
}
public void open (int combinationToTry) {
}
}
May 2004
NH-Chapter4
29
Structure for a simple test
class CombinationLockTest {
private CombinationLock lock;
public CombinationLockTest () {
}
public void runTest () {
}
}
public class TestCombinationLock {
public static void main (String[] argv) {
(new CombinationLockTest()).runTest();
}
}
May 2004
NH-Chapter4
30
Precondition
A condition client of a method must make sure holds
when method is invoked.
“Require”s : Constructor and method enter have
requirements that clients must meet for them to
execute properly.
May 2004
NH-Chapter4
31
Constructor specifications
/**
* Create a lock with the specified
combination.
*
* @require:
*
0 <= combination && combination <= 999
* @ensure:
*
this.isOpen()
*/
public CombinationLock (int combination) …
May 2004
NH-Chapter4
32
Testing locks
Need method to create and test lock with given combination:
private void testLock (int combination)
Test a lock with the specified combination.
Invoke this method in runTest for each lock to
test.
public void runTest () {
testLock(0);
testLock(123);
testLock(999);
}
May 2004
NH-Chapter4
33
Automating checking of test results
private void verify (boolean test, String message) {
if (!test)
System.out.println(
"Verification failed: " + message);
}
May 2004
NH-Chapter4
34
testLock method
testLock method must create lock and run initial
state test:
private void testLock (int combination) {
lock = new CombinationLock(combination);
testInitialState();
}
May 2004
NH-Chapter4
35
testLock method
Initial state test should make sure that lock is open.
So, instead of writing the test method:
private void testInitialState() {
System.out.println("Initial state: " +
lock.isOpen());
}
Write:
private void testInitialState() {
verify(lock.isOpen(), "initial state");
}
May 2004
NH-Chapter4
36
Class CombinationLock implementation
The straightforward implementations:
public CombinationLock (int combination) {
this.combination = combination;
this.isOpen = true;
}
public boolean isOpen () {
return isOpen;
}
May 2004
NH-Chapter4
37
Class CombinationLock implementation
In constructor, there are two variables with same name.
Component variable and
local variable combination.
this.combination refers to component variable.
If variable does not include object reference this in front
of it, it is a reference to local variable.
May 2004
NH-Chapter4
38
Class CombinationLock
implementation
May 2004
NH-Chapter4
39
Method to test close
write method to test close, and invoke it
from testLock:
private void testClose() {
lock.close();
verify(!lock.isOpen(), "close open lock");
lock.close();
verify(!lock.isOpen(), "close closed lock");
}
private void testLock (int combination) {
lock = new CombinationLock(combination);
testInitialState();
testClose();
}
May 2004
NH-Chapter4
40
Implementing close in Lock
Command close is also easy to implement:
public void close () {
isOpen = false;
}
May 2004
NH-Chapter4
41
Method to test open
Test for the method open: four cases to test:
closed lock, correct combination: lock opens;
open lock, correct combination: lock remains open;
closed lock, incorrect combination: lock remains closed.
open lock, incorrect combination: lock remains open;
Test depends on combination, so pass correct
combination as argument:
private void testOpen (int combination)
May 2004
NH-Chapter4
42
testOpen method
private void testOpen (int combination) {
int badCombination = (combination + 1) % 1000;
// test with correct combination:
lock.close();
lock.open(combination); // open closed lock
verify(lock.isOpen(), "open closed lock");
lock.open(combination); // open opened lock
verify(lock.isOpen(), "open opened lock");
// test with incorrect combination:
lock.open(badCombination); // try opened lock
verify(lock.isOpen(), "bad comb, opened lock");
lock.close();
lock.open(badCombination); // try closed lock
verify(!lock.isOpen(), "bad comb, closed lock");
}
May 2004
NH-Chapter4
43
testOpen method
Add an invocation of this method to testLock:
private void testLock (int combination) {
lock = new CombinationLock(combination);
testInitialState();
testClose();
testOpen(combination);
}
May 2004
NH-Chapter4
44
Method open implementation
The following implementation of open fails the tests.
public void open (int combination) {
isOpen = (this.combination == combination)
}
test will produce the following output:
Verification failed: bad comb, opened lock
Verification failed: bad comb, opened lock
Verification failed: bad comb, opened lock
Root of problem: attempt to open an already opened
lock with incorrect combination should not close it.
May 2004
NH-Chapter4
45
Method open implementation
Correct implementation of method uses a conditional
statement that opens the lock if the combination is correct, and
does nothing if the combination is not correct:
public void open (int combinationToTry) {
if (this.combination == combinationToTry)
isOpen = true;
}
May 2004
NH-Chapter4
46
Digit by digit lock
This lock has a 3 digit combination.
To open the lock, client provides the digits one at a time.
If client enters three digits of combination in order, lock
opens.
It doesn’t matter how many digits client provides, as long as
combination is given.
May 2004
NH-Chapter4
47
Digit by digit lock: combination 123
May 2004
Digit Entered
4
1
2
4
3
1
2
3
Lock Status
closed
closed
closed
closed
closed
closed
closed
open
Digit Entered
1
2
3
4
7
Lock Status
closed
closed
open
open
open
NH-Chapter4
48
Digit by digit lock: combination 123
if client gives command close when combination has been
partly entered,
Client Command
Lock Status
enter 1
enter 2
close
enter 3
closed
closed
closed
?
Client Command
Lock Status
enter 1
enter 2
close
enter 3
open
open
open
closed
?
command close resets lock, entire combination must be
entered.
May 2004
NH-Chapter4
49
Digit by digit lock
If combination is 123 and digits 1-2-2 are entered, we
need three digits to open the lock:
Digit Entered Lock Status
1 closed
2 closed
2 closed
(need 2-3 to open)
(need 3 to open)
(need 1-2-3 to open)
If combination is 223 and the digits 2-2-2 are
entered, a 3 will still open the lock:
Digit Entered Lock Status
2 closed
2 closed
2 closed
May 2004
(need 2-3 to open)
(need 3 to open)
(still need 3 to open)
NH-Chapter4
50
Class CombinationLock
Constructor:
public CombinationLock (int combination)
require: combination >= 0 && combination <=999
Queries:
public boolean isOpen ()
Commands:
public void close ()
public void enter (int digit)
require: digit >=0 && digit <=9
May 2004
NH-Chapter4
51
CombinationLock responsibilities
Know:
the 3-digit combination.
whether locked or unlocked.
the last three digits entered.
Do:
lock.
unlock, when given the proper combination.
accept a digit.
May 2004
NH-Chapter4
52
Getting digits from integers.
Using % and / operators, can extract each digit.
Suppose combination 123.
123 % 10 -> 3
123 / 10 -> 12
12 % 10 -> 2
12 / 10 -> 1
% 10 gets last digit
/ 10 gets remaining digits.
May 2004
NH-Chapter4
53
CombinationLock implementation
private boolean isOpen;
//
private int digit1;
//
private int digit2;
//
private int digit3;
//
// invariant:
// digit1 >= 0 && digit1 <= 9
// digit2 >= 0 && digit2 <= 9
// digit3 >= 0 && digit3 <= 9
May 2004
lock is unlocked
1st combination digit
2nd combination digit
3rd combination digit
&&
&&
NH-Chapter4
54
CombinationLock implementation
// last, secondToLast, thirdToLast are the last three
// digits entered, with last the most recent.
// a value of -1 indicates digit has not been entered.
private int last;
private int secondToLast;
private int thirdToLast;
// invariant:
// -1 <= last <= 9 &&
// -1 <= secondToLast <= 9 &&
// -1 <= thirdToLast <= 9
May 2004
NH-Chapter4
55
Combination is 223, and digits 2-2 have been entered
to a closed lock
Combinati onLock
May 2004
digit1
2
digit2
2
digit3
3
isO pen
false
t hirdTolast
-1
secondToLast
2
last
2
NH-Chapter4
56
Implementing constructor
public CombinationLock (int combination) {
digit3 = combination % 10;
combination = combination / 10;
digit2 = combination % 10;
digit1 = combination / 10;
isOpen = true;
last = -1;
secondToLast = -1;
thirdToLast = -1
}
May 2004
NH-Chapter4
57
Implementing methods
Query isOpen is the same as before.
public boolean isOpen () {
return isOpen;
}
Command close must resets lock.
public void close () {
open = false;
last = -1;
secondToLast = -1;
thirdToLast = -1;
}
May 2004
NH-Chapter4
58
Implementing method enter
public void enter (int digit) {
thirdToLast = secondToLast;
secondToLast = last;
last = digit;
if (thirdToLast == digit1 &&
secondToLast == digit2 && last == digit3)
isOpen = true;
}
May 2004
NH-Chapter4
59
Relational operators
<=
less than or equal
>
>=
==
!=
greater than
greater than or equal
equal (A single ‘=‘ denotes assignment.)
not equal
A relational expression consists of two expressions
joined with a relational operator.
May 2004
NH-Chapter4
60
Relational expressions
Let i1=10, i2=-20, i3=30.
i1 < 12
true
i1 <= 10
true
i3 == i1
false
i1 != 2
true
i1 < 10
false
i2 > 0
false
2*i1 == i2+40
true
i2*(-1) != i1+i1 false
May 2004
NH-Chapter4
61
Relational expressions
An expression like a<b<c is illegal.
int values are converted to double, in mixed type
comparisons:
10 > 2.5 10.0 > 2.5 false
May 2004
NH-Chapter4
62
Relational expressions
floating point values are approximations for real
numbers, avoid using equality or inequality operators
with them.
(1.0/6.0 + 1.0/6.0 + 1.0/6.0 +
1.0/6.0 + 1.0/6.0 + 1.0/6.0) == 1.0 false
May 2004
NH-Chapter4
63
Reference equality and object
equality
Operators == and != can be used to compare values
of any type.
Comparing reference values must be of same type.
Counter counter1;
Counter counter2;
Explorer myHero;
counter1 == counter2 // legal
counter1 == myHero
May 2004
// compilation error
NH-Chapter4
64
Reference equality and object
equality
Two reference values are equal if they refer to same object.
How to check if two different objects are equal?
if string1, string2, and string3 are String variables,
string1 = "c";
string2 = "ab" + string1;
string3 = "a" + "bc";
string2 and string3 will reference two distinct objects.
string2 == string3
false
use String method equals,
string2.equals(string3)
May 2004
true
NH-Chapter4
65
Boolean operators
!
&&
||
not
and
or
Use :
! booleanExpression
booleanExpression && booleanExpression
booleanExpression || booleanExpression
A boolean expression evaluates to true or false
May 2004
NH-Chapter4
66
The ! (not) operator
“Not” reverses boolean values.
!true false
!false true
Given : i1=10;
!( i1 > 9) !(true) false
Beware: “Not” has high precedence.
! i1 > 9 (!i1) > 9 illegal
May 2004
NH-Chapter4
67
&&, || (and then, or else)
operators
Given: i1=10;
(i1>10)||(i1==10)
(i1>10)||(i1<0)
(i1>0)&&(i1<5)
(i1>0)&&(i1<20)
May 2004
NH-Chapter4
false
false
true
true
||
||
&&
&&
true true
false false
false false
true true
68
&&, || (and then, or else)
operators
&& and || have lower precedence than the relational operators.
Parentheses are still useful as they enhance readability.
i1 < i2 && i1 < i3 means
(i1 < i2) && (i1 < i3)
Using the “and then” operator, can express the condition that
value of i1 is between 0 and 20:
(0 < i1) && (i1 < 20)
May 2004
NH-Chapter4
69
The && and || are lazy operators
They evaluate only the left operand only when that suffices.
Given i1=10;
(i1 < 10) && (i1 > 0) false && (i1 > 0) false
(i1 < 11) || (i1 > 100) true || (i1 > 100) true
Right operands, (i1 > 0) and (i1 > 100), are not evaluated.
Useful when considering expressions like
(x == 0) || (y/x < 10)
If left operand is true, x is 0, evaluating right operand will result in an attempt
to divide by 0 and a run-time error.
May 2004
NH-Chapter4
70
Operator precedence
High
unary +, unary -,
*, /, %
+, <, <=, >, >=
==, !=
&&
||
!
Low
May 2004
NH-Chapter4
71
DeMorgan’s Laws
Useful for simplifying expressions.
!(b1 && b2) !b1 || !b2
!(b1 || b2) !b1 && !b2
!(i1>5 && i1<8) !(i1>5) || !(i1<8)
May 2004
NH-Chapter4
72
Summary
Introduced boolean expressions and conditional
statements.
Conditional statements allow us to specify alternative
computations and the circumstances under which
each is to be performed.
The particular action to be done is determined by the
processor at execution time, depending on the current
data values.
May 2004
NH-Chapter4
73
Summary
The two forms of conditional statement we’ve seen are
if-then and if-then-else.
if (condition)
statement
With an if-then-else, we specify two possible actions,
one of which will be done:
if (condition)
statement1
else
statement2
May 2004
NH-Chapter4
74
Summary
Syntax of the Java language permits only a single statement as
a conditional alternative.
Need a way to package a number of statements into one.
Compound statement: put braces around a sequence of
statements:
{ statement1 statement2 … statementn }
May 2004
NH-Chapter4
75
Summary
Boolean expression: an expression that evaluates to a
boolean value, true or false.
Several kinds of operators useful for constructing boolean
expressions:
relational operators <, <=, >, and >=,
equality operators == and !=,
boolean operators &&, ||, and !.
May 2004
NH-Chapter4
76
Summary
introduced preconditions, postconditions, and invariants.
Important in the specification and correctness verification of
our designs.
Not part of the language per se, we include them in comments.
May 2004
NH-Chapter4
77
Summary
Client of a method responsible for making sure that all method
preconditions are satisfied before invoking method.
Method will work correctly only if preconditions are satisfied.
Preconditions are documented in a require clause of method
specification.
May 2004
NH-Chapter4
78
Summary
Method implementor is responsible for making sure that all
postconditions are satisfied when method completes.
Postconditions documented in an “ensure clause” of method
specification.
May 2004
NH-Chapter4
79
Summary
Invariants are conditions that always hold.
Class invariants are conditions that are always true of all
instances of a class.
A class instance is a consistent and coherent model of whatever
entity the class represents if class invariants hold.
May 2004
NH-Chapter4
80
© Copyright 2026 Paperzz