|
Second Summer 2002
|
Lecture Notes Six:
Boolean values, expressions, and if statements.
What's this?
x < 15
|
A boolean expression: an expression
whose value is either true or false .
|
Can you define boolean variables in Java?
|
Sure, boolean is a primitive type in Java.
|
boolean b;
|
b can only hold true and
false values.
|
What are the primitive types in Java?
-
int, byte, short, long
-
double, float
-
boolean
-
char
|
There are four kinds:
- whole numbers
- floating-point numbers
- boolean values
- characters
|
We've seen int , and double values...
|
... we now take a look at boolean values.
|
How do you read this?
x <= 15
|
"x is less than or equal to 15"
|
How do you write "x is in between 9 and 15"?
|
First, what value does it have: true or false ?
|
We don't know yet, it depends on what x is.
|
So we might as well call it p (x).
|
Very well; now we can look at it for particular values of x.
|
p (3) is false
|
p (20) also is false
|
Come to think of it, p (x) is false for many values.
|
What's p (x) again?
|
A statement about x being between 9 and 15.
|
When is it true ?
|
When
x <= 15
and at the same time
x >= 9
|
How do you write AND in Java?
|
&&
|
So p (x) can be written as:
|
&& is read as AND
|
(x >= 9) && (x <= 15)
And || is read as OR.
|
While ! stands for NOT in Java.
|
I like A201 !
|
I do ! think this is that funny...
|
So && , || , and
are operators for truth values.
|
Yes. How do they work?
|
p |
q |
p && q |
p || q |
! q |
true |
true |
true |
true |
false |
true |
false |
false |
true |
true |
false |
true |
false |
true |
|
false |
false |
false |
false |
|
|
|
AND |
OR |
NOT |
|
So && works in the following way: you graduate if you
satisfy both of two requirements.
|
Otherwise you don't graduate.
|
|| is a bit more lenient.
|
You graduate if you satisfy at least one of the
two requirements.
|
And only when none of them has been satisfied you do not graduate.
|
And ! is easy.
|
It is, indeed.
|
The boolean type is called after mathematician
George Boole, a pioneer in the study of logic.
|
Logic is tricky: suppose a is a boolean
value, true or false . What value does
a || !a
|
Doesn't it depend on the value of a ?
|
No.
|
Well, then let's look at all possible cases:
| |
a |
! a |
a || (! a) |
true |
false |
true |
false |
true |
true |
|
Doesn't it look easy now?
|
Yes, and there weren't even too many cases.
| How do you compute?
3 + 5 * 2
|
Why are you bringing this up?
|
Because as you know there is an implicit order of evaluation for arithmetic
expressions.
|
Does a similar set of rules apply to boolean expressions?
|
Yes. In arithmetic, unary minuses are taken into account before
we do any multiplications...
|
... and only after that we may do addtions, if any.
|
If there are no parentheses, otherwise the parens dictate the order of evaluation.
|
What rules govern the order of evaluation for
&& , || , and ! ?
|
! has the highest priority. Then comes && ,
and the || has the lowest priority.
|
So if you look at
a || b && ! c
|
It's evaluated as
a || (b && (! c))
|
What is the truth table for
!a && !b
|
Let's build it at the same time for
!(a || b)
|
a |
b |
a && b |
!(a && b) |
!a |
!b |
!a || !b |
true |
true |
true |
false |
false |
false |
false |
true |
false |
false |
true |
false |
true |
true |
false |
true |
false |
true |
true |
false |
true |
false |
false |
false |
true |
true |
true |
true |
We have just proved one of DeMorgan's law.
|
What is the other one?
|
It's the dual of this:
!(a || b)
|
is the same as
!a && !b
|
There are many other identities that one can prove.
|
Perhaps we can do that later, as needed.
|
Yes, but let me give some examples, in case you get
bored and want to practice.
|
Sure.
|
This
|
... is the same as this
|
a && (b || c)
|
a && b || a && c
|
Let's face it: boolean s can make you dizzy.
|
Yes, but they are clearly necessary.
|
For example, the programs we have seen so far are fairly inflexible.
|
Except for variations in the input they work the same way
with every program run.
|
One of the essential features of nontrivial computer
programs is the ability to make decisions...
|
... and to carry out different actions, depending on the nature of the inputs.
|
With boolean s one can
program simple and complex decisions.
|
Learning that will greatly increase our expressive power in Java.
|
In some of the previous assignments we went to great length to either
avoid,...
|
... or fake decisions by building them into clever formulas.
|
Being able to make decisions would greatly simplify those programs.
|
The if/else statement is used to implement a decision
in a program. The if/else statement has three parts:
- a test (a
boolean expression),
- a then branch, and
- an else alternative.
|
If the test succeeds, the body of the then branch,
|
... also known as the body of the if statement,
|
... is executed.
Here's an example, as a flowchart:
|
This is from problem P2.3 of last week.
|
And in Java:
if (x > y) { max = x; }
else { max = y; }
|
The condition is red, the body of the if
statement is blue, while the body of the else
alternative appears in green.
|
A statement such as
max = x;
is called a simple statement.
|
A conditional statement, such as:
if (x > 0) { y = x; }
else { y = -x; }
is called a compound statement.
|
By the way, this last compound statement could be replaced by
(as it's equivalent to):
y = Math.abs(x);
|
I know, but that's only because it's so simple.
|
Our programs remain sequences of statements, we just allow
compound statements, such as if statements, in.
|
But remember: Your programs now become
essentially two-dimensional.
|
Quite often the body of an if statement consists of multiple
statements that must be executed in sequence whenever the test is succesful.
|
These statements must be grouped together to form a block statement by
enclosing them in braces: { and } .
|
Also, while an if statement must have a test
and a body, the else alternative is optional.
|
I want to see examples.
|
Here's one, a bit contrived:
if (x < y) {
temp = x;
x = y;
y = temp;
}
|
We assume, of course, that x , y , and
temp have been declared, and that x and
y , at least, have been initialized already.
|
Can you briefly say what the code is doing?
|
It makes sure that of the two values the larger one is always in x .
|
Very good. What were we saying about braces?
|
They group statements together.
|
What if we drop them?
|
Then the code no longer works as intended.
|
So what is the syntax of an if statement? |
The body of an if statement (or an else alternative) must be
a statement (just one).
|
But it can be:
- a simple statement
- a compound statement (such as another
if statement), or
- a block statement
|
|
It's good to get into the habit of using braces (and thus block statements) all the time.
|
Yes, as we will see when we get to exercises, shortly.
|
I can hardly wait. But first, let's analyze the
if statement closer, and look at what
makes a test.
|
Its outcome is either true or false .
|
In many cases the test compares two values.
|
Comparison operators such as <= are
called relational operators.
|
Java has six relational operators.
|
Java | Math | Description |
> |
> | Greater than |
>= |
| Greater than or equal |
< |
< | Less than |
<= |
| Less than or equal |
== |
= | Equal |
!= |
| Not equal |
The == operator is initially confusing to
most newcomers to Java.
|
In Java, the = symbol already has a meaning,
namely assignment.
|
The == denotes equality testing:
|
|
a = 5; // assign 5 to a
if (a == 3) // tests whether a equals 3
System.out.println("a is equal to 3");
else
System.out.println("a is not equal to 3");
|
You will have to remember to use == for equality testing and
to use = for assignment.
|
Floating point numbers have only a limited precision, and
calculations can introduce roundoff errors.
|
That means we need to be careful when we want to test if two floating
point quantities are representing the same thing.
|
double r = Math.sqrt(2);
if (r * r == 2)
System.out.println(r * r + " == 2");
else
System.out.println(r * r + " != 2");
|
Unfortunately such roundoff errors are unavoidable.
|
In most circumstances it does not make a lot of sense to
compare floating point numbers exactly.
|
Instead we should test whether they're close enough.
|
That is, the absolute value of their difference should be less than some threshold.
|
Mathematically, x and y are close enough if

|
... for a very small number, .
|
Greek letter epsilon is commonly used to denote a very small quantity.
|
It is common to set
to 10-14 when comparing double
numbers.
|
However, this is not always good enough.
|
Indeed, if the two numbers are very big, then one can be a
roundoff of the other even if their difference is much bigger
than 10-14.
|
To overcome this problem we need to normalize: we divide
by the magnitude of the numbers before comparing how close
they are.
|
So x and y are close enough if

|
And to avoid division by zero it is better to test whether

|
Math.abs(x - y) <= EPSILON * Math.max(Math.abs(x), Math.abs(y))
|
OK, I think I understand how I test numbers
(integers or floating point) for equality.
|
What else can we test for equality?
|
How about String s?
|
To test whether two strings are equal to each other, ...
|
..., that is, that their contents is the same, ...
|
... one must use method equals .
|
Why not use == like for numbers?
|
String s are objects.
|
And so are Rectangle s.
|
If you compare two object references with the
== operator, ...
|
... you test whether the references
refer to the same object.
|
That's because you check to see whether the two locations contain the same thing.
|
Which is in each case an address, to an actual object.
|
Rectangle a = new Rectangle(5, 10, 20, 30);
Rectangle b = a;
Rectangle c = new Rectangle(5, 10, 20, 30);
|
The comparison a == b is true .
|
Both object variables refer to the same object.
|
But the comparison a == c is false .
|
The two object variables refer to different objects.
| |

|
It does not matter that the objects have identical contents.
|
You can use the equals method to test whether two rectangle have the same contents.
|
Thus a.equals(c) is true .
|
And so is c.equals(b) obviously.
|
Same with String s, so we will have to remember to use equals for string comparison.
|
In Java letter case matters.
Thus "harry".equals("HARRY") evaluates to false .
|
But "harry".equalsIgnoreCase("HARRY") evaluates to true .
|
Even if two strings don't have "identical" contents
we may still want to know the relationship between them.
|
The compareTo method compares strings in dictionary order.
|
If string1.comparesTo(string2) < 0
|
... then string1 comes before string2 in dictionary order.
|
If string1.comparesTo(string2) > 0
|
... then string1 comes after string2 in dictionary order.
|
If string1.comparesTo(string2) == 0
|
... then the two strings have identical contents.
|
You should look this method up in class String .
|
Actually the dictionary ordering used by Java is slightly different from that of a normal dictionary.
|
Java is case-sensitive and sorts characters
by listing numbers first, then uppercase characters, then lowercase characters.
|
For example 1 comes before B which comes before a .
|
And the space character comes before all other characters.
|
Can we describe the comparison process a little bit in greater detail?
|
When comparing two strings, corresponding letters are compared until one of the strings ends
or the first difference is encountered.
|
If one of the strings ends, the longer string is considered the later one.
|
If a character mismatch is found, compare the characters to determine which string comes later
in the dictionary sequence.
|
The process is called lexicographic comparison.
|
That's
why "car" comes before "cargo" ,
|
And "cathode" comes after "cargo" in lexicographic ordering.
|
Time for a break. |
I sure think so.
|
And some exercises too.
|
Yes, but the break first, please.
|
OK, here's what we'll do: we'll put the exercises
into the break altogether. |
And combine the useful with the necessary.
|
The text of the problem is always the same.
|
I know it: "What is the output produced by the
following snippets of code when embedded in
a complete program."
|
Snippet 1:
int x = 3;
if (2 > x)
System.out.print(1);
else
System.out.print(2);
if (x < 2)
System.out.println(3);
System.out.print(4);
|
Easy. Draw a diagram.
|
Snippet 2:
int x = 3;
if (x > 5) {
if (x < 10)
System.out.print(1); }
else
System.out.print(2);
System.out.print(3);
|
Messy. The curly braces change everything.
|
What if you take them out?
|
The diagram changes significantly.
|
And you have experienced a dangling else.
|
That's right.
|
int x = 3;
if (x > 0) System.out.print(x + 1);
else if (x > 1) System.out.print(x);
else if (x > 2) System.out.print(x - 1);
else if (x > 3) System.out.print(2 * x);
else System.out.print(x * x);
int x = 3;
if (x > 0) System.out.print(x + 1);
else if (x > 1) System.out.print(x);
else if (x > 2) System.out.print(x - 1);
else if (x > 3) System.out.print(2 * x);
else System.out.print(x * x);
|
Who would ever do that in a program?
|
Nobody. It's for practice.
|
Messy again. You have to redraw everything.
|
I agree it's messy, but is it hard?
|
No. Is this the last one?
|
Yes.
|
Can we do a reasonable example now?
|
OK, here's problem 19 from problem set 1.
| |
/* Solution to problem nineteen in the first problem set. Use
ConsoleReader from lab notes 2 as explained. The trick here (as
hinted in the text) is to transform a number for a month in a
position (index) in the string where the month name is starting,
all names being made of the same length, and then concatenated
together in one final string. */
public class Nineteen {
public static void main(String[] args) {
String monthNames = "January " +
"February " +
"March " +
"April " +
"May " +
"June " +
"July " +
"August " +
"September " + // longest
"October " +
"November " +
"December " ;
// open a connection with the keyboard
ConsoleReader console = new ConsoleReader(System.in);
// greet the user, and ask for input
System.out.println("Please enter a month number from 1 to 12.");
// get month name
int month = console.readInt();
// report the name of the month
System.out.println(
monthNames.substring("September ".length() * (month-1),
"September ".length()*month));
// formula uses the length of the longest name
}
}
|
Here is it with if statements:
|
public class P19 {
public static void main(String[] args) {
ConsoleReader console = new ConsoleReader(System.in);
System.out.println("Please enter a month number from 1 to 12.");
int month = console.readInt();
if (month == 12) System.out.println("December");
else if (month == 11) System.out.println("November");
else if (month == 10) System.out.println("October");
else if (month == 9) System.out.println("September");
else if (month == 8) System.out.println("August");
else if (month == 7) System.out.println("July");
else if (month == 6) System.out.println("June");
else if (month == 5) System.out.println("May");
else if (month == 4) System.out.println("April");
else if (month == 3) System.out.println("March");
else if (month == 2) System.out.println("February");
else if (month == 1) System.out.println("January");
}
}
I thought we agreed to use block statements (with curly braces)
for the bodies of if statements and else
alternatives all the time.
|
Yes, but just for once I wanted to keep the code somewhat shorter.
|
Well, then, just for once, I have two more exercises.
|
OK, I will remember to put braces from now on, always.
|
Too late.
|
Show me the first exercise.
|
Here it is:
|
Can't be true !
|
if (false && false || true) {
System.out.print(false);
} else {
System.out.print(true);
}
Snippet 2:
|
I can see the difference.
|
if (false && (false || true)) {
System.out.print(false);
} else {
System.out.print(true);
}
I'm sure you do.
|
That's probably true or false .
|
Last updated: Jun 16, 2002 by Adrian German for A201
|