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?

Let me draw a table.
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

a || true
true

a && true
a

a || false
a

a && false
false

a == true
a

a == false
! a

Let's face it: booleans 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 booleans 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.

Here's an example:
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

In Java, this is:
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 Strings?

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?

Strings are objects. And so are Rectangles.

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.

Let's see some examples.
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 Strings, 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."

Let's see the snippets.
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.

Snippet 3:
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);
Easy. Diagram it.

Snippet 4 (and last):
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