home—info—lects—labs—exams—hws
tutor/PIs—breeze (snow day)
Object120 + its docs—java.lang docs—java.util docs
lect05a
boolean connectives: and, or, not
boolean connectives: &&, ||, !
The boolean functions are
&&
(“and”)
and
||
(“or”).
For instance,
((30 <= choice) && (choice < 33)) |
reads as
“choice is at least thirty,
and less than 33”.
Similarly,
((newFace < 1) || (newFace > NUM_SIDES)) |
tests
for newFace being less than 1,
or bigger than NUM_SIDES.
In general, && looks at the boolean expressions
on each side,
and the entire && will evaluate to true
if (and only if)
the left side and the right side evaluate to true:
expr1 |
expr2 |
(expr1&&expr2) |
false |
false |
false |
false |
true |
false |
true |
false |
false |
true |
true |
true |
(expr1
and expr2
can be any other boolean
expression—including more-deeply-nested and/or expressions!)
Complementing &&,
an entire || expression evaluates
to true
if (and only if) one side or the other evaluates to true:
expr1 |
expr2 |
(expr1||expr2) |
false |
false |
false |
false |
true |
true |
true |
false |
true |
true |
true |
true |
Really, you can think of && as a function
with the signature
boolean &&( boolean b1, boolean b2 )
(although, like arithmetic1, we write them in infix notation,
with the function-name coming inbetween its two inputs, rather
than in-front-of-them-with-parentheses).
Exercise:
What is the value of:
( ((3 <= 7) || (4 == (2+3))) && (Math.sqrt(4) > 0.0) )
|
This is just like solving an arithmetic problem, except
that we are dealing with true and false
instead of all the integers2.
It's worth a mention that in English, “or” is used in two different
ways:
The inclusive-or, which is what || means,
means “one or the other or both”.
For example, if the question on the tax form asks
“are you over 18, or had income of more than $20,000”,
and you meet both criteria, then the answer is true.
(People might use “and/or” to emphasize they include the
“and” part.)
However, sometimes English uses “or” to mean one or the other
but not both.
For instance,
“You can eat veal, or you can be morally responsible”
is implying that one option precludes the other.
(You may or may not agree with that presumption, of course.)
Similarly, if you are told
“Keep dating your ex, or date me!”,
don't presume that the option of both is included in the “or”!
While we're on the topic, there is one last boolean operator,
! (“not”):
expr |
!expr |
false |
true |
true |
false |
So (2+2 == 4) is true,
but !(2+2 == 4) is false.
This could also have been written directly using the not-equals operator:
(2+2 != 4).
Exercise:
What is
-
(true || true) && false
-
true || (true && false)
-
true || true && false, without any parentheses?
Yikes, while Java might have some rules for this, the real answer is:
whenever there's the slightest doubt, add parentheses.
Let's revisit mustRegisterForDraft.
The current laws are a bit different from what is shown:
only men aged 18-25 must register.
Update our function accordingly:
/**
* @param age The age (in years) of the person in question. E.g., 18months is age 1.
* @param ___ _______________________________________________
* @return whether or not the person must register with Selective Service.
* mustRegisterForDraft_v2( 0, ___) == false
* mustRegisterForDraft_v2( 0, ___) == false
* mustRegisterForDraft_v2(17, ___) == false
* mustRegisterForDraft_v2(18, ___) == true
* mustRegisterForDraft_v2(22, ___) == true
* mustRegisterForDraft_v2(22, ___) == false
* mustRegisterForDraft_v2(25, ___) == _______
* mustRegisterForDraft_v2(27, ___) == _______
*/
boolean mustRegisterForDraft_v2( int age, ____ ______ ) {
return _ (age >= 18) __ ________ __ _______ _;
}
|
solution
/**
* @param age The age (in years) of the person in question. E.g., 18months is age 1.
* @param isFemale Is the person in question female?
* @return whether or not the person must register with Selective Service.
* mustRegisterForDraft_v2( 0, true ) == false
* mustRegisterForDraft_v2( 0, false) == false
* mustRegisterForDraft_v2(17, false) == false
* mustRegisterForDraft_v2(18, false) == true
* mustRegisterForDraft_v2(22, false) == true
* mustRegisterForDraft_v2(22, true ) == false
* mustRegisterForDraft_v2(25, false) == true
* mustRegisterForDraft_v2(27, false) == false
*/
boolean mustRegisterForDraft_v2( int age, boolean isFemale ) {
return ( (age >= 18) && (age <= 25) && !isFemale );
}
|
By the way, now we see more clearly, the advantage of making this
its own function -- we don't have to update the rules in several places.
In fact, we'll need to update our function further, to account
for whether the person is a U.S. citizen, or an alien living in the U.S.
In fact, ultimately your code should be a direct translation
of the actual regulations,
which can be fairly detailed.
home—info—lects—labs—exams—hws
tutor/PIs—breeze (snow day)
Object120 + its docs—java.lang docs—java.util docs
Naming convention: start boolean variable names
with a word to make it clear that the variable stores a true/false value:
“isHappy”,
“hasAllPrereqs”,
etc.
Aside:
Some languages — not Java — allow “?”
to be part of a name;
in those languages boolean variables are often named
“happy?”,
“hasAllPrereqs?”.
Since functions which return a boolean value are sometimes
called “predicates”, some people use the letter “p”
to indicate a predicate function:
“isPrimeP(int n)”,
“flightIsBookedP( int flightNum )”.
Reflections on if-else-if
Here's another example of if-else-if:
/** Return a greeting, selected randomly from a list of several greetings.
* @return A greeting (randomly selected, not necessarily uniformly).
*/
String greet() {
int choice = Object120.random(100); // a number in [0,100) -- a.k.a. 0..99.
String msg;
if (choice < 30) {
msg = "Hello.";
}
else if (choice < 33) {
msg = "Aloha.";
}
else if (choice < 50) {
msg = "Buenos dias, amigo/amiga.";
}
else if (choice < 99) {
msg = "Yo.";
}
else if (choice < 100) {
// Not an advisable greeting. Use sparingly.
msg = "I am a javabot: System dot out dot println open \"hello\" close.";
}
else {
System.err.println( "Uh-oh, I didn't expect to reach here!" );
msg = "A dummy initialization for `msg`, to appease the compiler.";
}
return msg;
}
|
Some discussions:
-
Instead of initializing a variable, we could have included
a return in each branch.
Note that the return statement means
“stop this function right now, and return an answer”.
In that approach, 3
the line at the end will never actually be reached,
because one of the return statements will be selected
first.
- If choice is initialized with the value 30,
what number is returned? How about 34?
- What is the probability of returning Hello?
How about Aloha?
Half-open intervals make this answer easy
(no having to decide whether add one or to subtract one)!
- Is the choice < 100 branch actually ever taken?
- What if we change “< 100”
to “<= 100”?
- What if we change “< 99”
to “<= 99”?
- If we leave off the “appeasing” return statement,
the program doesn't compile; java complains “possible to
reach end of function without a return statement”.
Why?
Discuss.
- More fundamentally:
Should the if (choice < 100) be omitted, so that it is
the catch-all else?
Consider—what if we have some mistake in our series of cases (say,
accidentally leaving off the case, for some intermediate range of numbers)?
Can the compiler catch such a mistake automatically?
guideline:
If your last condition is easy to phrase (as it is here),
then certainly include it,
making the last else unreachable.
But don't bend over backwards, to do this; sometimes formulating
that final condition is more error-prone than the savings you'd get!
Mention:
Arguably, it is bad to have more than one return in a method;
(rather than always reaching the end of the method and returning a value there,
for everybody to easily see).
Myself, I consider an if-else-if where each branch returns
as kinda like a single return.
But others don't see it this way, and may chide you for having more
than one exit-point from your function.
Technicalities with if statements
-
You will see
other people use arguably poor style,
where they
initialize a variable to a potentially-wrong value,
and then go back and correct it when needed:
String slicesReadyMsg( String topping, int slicesReady ) {
String verbForm = "are"; // The correct verb for our result.
String plurality = "s"; // The noun-suffix, correctly plural or singular.
// Note that at this moment, our variables may or may
// hold their correct values.
if (numInStock == 1) {
verbForm = "is";
plurality = "";
} // `if` without `else` is legal Java.
return "There " + verbForm + " "
+ slicesReady +
+ " piping hot slices of "
+ topping + ("pizza" + plurality)
+ " in stock.";
}
|
In this version, you can't point to a single statement which initializes
the variable;
people maintaining this code in the future
might miss the 'second initialization',
if they need to alter the initialization.
-
When there is only a single statement in the body (between the curly-braces),
the book reveals that you can conceivably omit the curly-brackets.
4
optional:
The following explanation is optional, and will be skipped in lecture,
as long as you read the concluding
edict below.)
Alas, omitting the brackets is bad for several reasons:
-
It's fairly common that you decide later to go back and add
something to the if- or else- case, and you end up adding the brackets
later.
Moreover, if you have several lines in a block and delete them down
to just one, you'd want to delete the brackets to be consistent
(and not cause readers to wonder if there is some unintentional bug).
-
This usually leads to confusion though, and the book has to spend
several minutes talking about dangling elses.
-
Consider:
if (numInStock == 1)
verbForm = "is";
else
verbForm = "are";
|
What if we go back, and decide to add the lines for plurality,
but we forget to put in curly-braces?:
if (numInStock == 1) // missing curly-bracket?
verbForm = "is";
plurality = ""; // DANGER, WILL ROBINSON! -- this statement always reached!
else
verbForm = "are";
plurality = "s";
|
Java gives an error “else without an if” -- why?
If we hadn't had any else statement at all,
would we have caught our error?
Edict:
Even if you have only one line inside
an if- or else- block,
include curly-braces.
One exception:
-
If the statement is so short it easily fits on the same line
as the if or else keyword, you
can put it on the same line (without curly-braces).
(But don't be surprised if you find yourself later going back
and adding more to that line, which will then require the curly-braces.)
1Just like we think of +
and * as functions which take in two numbers, and return
a number. ↩
2If you look at the tables and
squint, thinking of false,true being like
0,1
and ||,&& being like +,*
then these tables above really do look fairly similar to arithmetic.
↩
3
So we could conceivably use
a series of if statements (without else),
rather than a big if-else.
The second if statement is only reached when the
first condition wasn't true (because in that case we'd return
before ever reaching the second if condition).
↩
4If we can omit curly-brackets,
we realize that the actual syntax for Java's if-else statement is
if (condition)
statement
else
statement
|
This is actually a general case of the version-with-brackets, given in these notes.
Why? Because along with assignment statments and return statements
and if statements, there is a block statement,
which looks like { statements… }.
↩
home—info—lects—labs—exams—hws
tutor/PIs—breeze (snow day)
Object120 + its docs—java.lang docs—java.util docs