2.5.1 Reversing a Condition with NOT
So far, every condition you have written asks one question: is the score at least 90? Is the password equal to "open"? Real decisions are often built from several questions. A movie theater sells a teen ticket when a customer is at least 13 and at most 19. A museum lets you in free when you are under 5 or at least 65. A phone warns you when the battery is not above 20 percent. Java has three operators for combining and flipping true-or-false values like these. This chapter teaches all three, starting with the simplest: “not.”
Recall from Topic 1.2 that a boolean holds exactly one of two values, true or false, and from Topic 2.2 that a comparison such as battery > 20 produces a boolean. Sometimes the value you have is the opposite of the one you want. You have a variable that says whether it is raining, but you want to know whether it is dry. In everyday language you just say “not raining.” Java lets you do the same thing.
A logical operator is an operator whose operands are boolean values and whose result is a boolean value. The first one is the NOT operator, written ! (an exclamation mark). It goes in front of a single boolean value and produces the opposite value:
a |
!a |
|---|---|
true |
false |
false |
true |
Read !isRaining aloud as “not is raining,” or more naturally, “it is not raining.” The ! takes one operand, the value right after it.
Key idea
!a is true when a is false, and false when a is true. NOT flips a boolean value.Worked example: Flipping a boolean variable
Watch which variables change and which do not.
boolean isRaining = true;
boolean isDry = !isRaining;
System.out.println(isRaining);
System.out.println(isDry);
System.out.println(!isDry);| Line | What Java does | isRaining |
isDry |
Printed |
|---|---|---|---|---|
| 1 | Stores true. |
true | ||
| 2 | Evaluates !isRaining: not true is false. Stores false. |
true | false | |
| 3 | Prints isRaining. |
true | false | true |
| 4 | Prints isDry. |
true | false | false |
| 5 | Evaluates !isDry: not false is true. Prints it. |
true | false | true |
Output:
true
false
trueTwo details matter here. First, !isRaining on line 2 did not change isRaining; it still holds true afterward. Like battery + 1, the expression !isRaining produces a new value and leaves the variable alone. Only an assignment changes a variable. Second, line 5 shows that ! can be used anywhere a boolean value can, including right inside println.
Now vary one thing: instead of flipping a boolean variable, flip the result of a comparison. A phone should warn you when the battery is not above 20 percent. You can write the comparison battery > 20, wrap it in parentheses, and put ! in front.
Worked example: Flipping a comparison
int battery = 15;
if (!(battery > 20))
{
System.out.println("Plug in your phone.");
}
else
{
System.out.println("Battery is fine.");
}Java works from the inside out:
| Step | Expression | Value |
|---|---|---|
| 1 | battery > 20 |
false |
| 2 | !(false) |
true |
| 3 | Condition is true |
run the if body |
Output:
Plug in your phone.The parentheses make Java finish the comparison first and then flip its result. If battery held 80, step 1 would be true, step 2 would be false, and the else body would print Battery is fine. instead.
Watch out
Leaving out the parentheses around a comparison. It is natural to write “not battery greater than 20” exactly as it sounds:
int battery = 15;
if (!battery > 20)
{
System.out.println("Plug in your phone.");
}This does not compile. Java reports something like:
error: bad operand type int for unary operator '!'Here is why. ! grabs only the single value right after it, and it grabs it before any comparison happens. So Java reads line 2 as (!battery) > 20. But battery is an int, and “not 15” means nothing: ! works only on boolean values. (“Unary” means the operator takes one operand.) The fix is to put parentheses around the whole comparison so it becomes a boolean first: !(battery > 20). (Exact error wording can vary between Java versions.)
Pause and try
Question 1 · Tracing
What does this code print? Track both variables line by line.
boolean lightsOn = false;
boolean dark = !lightsOn;
lightsOn = !lightsOn;
System.out.println(lightsOn);
System.out.println(dark);
System.out.println(!dark);Check your reasoning
It prints:
true
true
false| Line | What Java does | lightsOn |
dark |
|---|---|---|---|
| 1 | Stores false. |
false | |
| 2 | !false is true; store it in dark. |
false | true |
| 3 | !false is true; store it back in lightsOn. |
true | true |
| 4–6 | Print lightsOn, dark, then !dark. |
true | true |
The trap is line 3. It changes lightsOn, but dark was given a copy of a value on line 2 and is not recalculated, so dark stays true. Line 6 prints !true, which is false. Line 3 also shows a handy pattern: lightsOn = !lightsOn; switches a boolean to its opposite, like flipping a light switch.
Reread 2.5.1 Reversing a Condition with NOT if your answer differed.
Question 2 · Multiple choice
temp is an int. Which expression is true exactly when temp is not greater than 100?
!(temp > 100)!temp > 100!(temp < 100)temp != 100
Check your reasoning
A. The parentheses make Java evaluate temp > 100 first, and ! flips that result. When temp is above 100 the comparison is true and the whole expression is false; otherwise it is true.
- B is wrong: it does not compile.
!applies totempalone before the comparison, and!cannot be used on anint. - C is wrong:
!(temp < 100)istruewhentempis not less than 100, for example150. That is the opposite of what was asked for large temperatures. - D is wrong:
temp != 100means “not equal to 100.” Fortempequal to150it istrue, even though 150 is greater than 100.
Reread 2.5.1 Reversing a Condition with NOT if you chose differently.
2.5.2 Requiring Both Conditions with AND
A theater sells a teen ticket to anyone from 13 through 19 years old. One comparison cannot check that: age >= 13 lets in a 40-year-old, and age <= 19 lets in a 6-year-old. The customer has to pass both tests.
With Topic 2.4 you could already do this with a nested if:
if (age >= 13)
{
if (age <= 19)
{
System.out.println("Teen ticket");
}
}
That works, but it takes two if statements and two levels of braces to say one simple thing: “13 or older, and 19 or younger.” Java lets you say it in a single condition.
The AND operator, written && (two ampersands), combines two boolean values. The result is true only when both values are true; if either one is false, the result is false. It works like a door with two locks: it opens only when both locks are open.
a |
b |
a && b |
|---|---|---|
true |
true |
true |
true |
false |
false |
false |
true |
false |
false |
false |
false |
Now the teen check is one condition: age >= 13 && age <= 19. An expression like this, built from smaller boolean expressions joined by logical operators, is called a compound Boolean expression. However many pieces it has, it always evaluates to one boolean value, true or false, so it can go anywhere a boolean can: in an if condition, in a boolean variable, or in println.
Key idea
a && b is true only when both a and b are true. If either side is false, the whole expression is false.
Worked example: Checking an age range
The same condition is evaluated twice, with two different ages.
int age = 16;
boolean isTeen = age >= 13 && age <= 19;
System.out.println(isTeen);
age = 22;
isTeen = age >= 13 && age <= 19;
System.out.println(isTeen);Java evaluates each comparison to a boolean first and then combines the two results with &&:
| Line | age |
age >= 13 |
age <= 19 |
&& result |
|---|---|---|---|---|
| 2 | 16 | true |
true |
true |
| 5 | 22 | true |
false |
false |
Output:
true
falseFor 22, the first test passes, but one passing test is not enough for &&. Line 5 also shows that the condition does not update by itself when age changes: line 5 has to evaluate it again and store the new result.
Now vary the operands. The two sides of && do not have to be comparisons; any boolean values work, including boolean variables. And the result can control an if-else directly.
Worked example: Two boolean variables in an if-else
A student can drive to school only with a license and a car.
boolean hasLicense = true;
boolean hasCar = false;
if (hasLicense && hasCar)
{
System.out.println("You can drive to school.");
}
else
{
System.out.println("Take the bus.");
}hasLicense is true and hasCar is false. That is the second row of the table: true && false is false. The condition is false, so the else body runs:
Take the bus.Notice there is no == true in the condition. hasLicense already holds a boolean, so it can be used as an operand as it is.
Watch out
Chaining comparisons the way math does. In math class, 13 ≤ age ≤ 19 is a normal way to write a range, so students try the same thing in Java:
int age = 16;
if (13 <= age <= 19)
{
System.out.println("Teen ticket");
}This does not compile. Java reports something like:
error: bad operand types for binary operator '<='
first type: boolean
second type: intJava does not read the range as one idea. It evaluates 13 <= age first, which gives true. That leaves true <= 19, and a boolean cannot be compared with a number using <=. Java has no way to ask whether true is less than 19. The fix is to write both comparisons in full and join them with &&:
int age = 16;
if (13 <= age && age <= 19)
{
System.out.println("Teen ticket");
}This prints Teen ticket. (Exact error wording can vary between Java versions.)
Pause and try
Question 3 · Tracing
A picnic needs sun and a temperature strictly between 60 and 85. What does this code print?
int temp = 68;
boolean sunny = true;
boolean picnic = sunny && temp > 60 && temp < 85;
System.out.println(picnic);
temp = 90;
picnic = sunny && temp > 60 && temp < 85;
System.out.println(picnic);Check your reasoning
It prints:
true
falseWith three operands joined by &&, every one must be true.
| Line | sunny |
temp > 60 |
temp < 85 |
Result |
|---|---|---|---|---|
| 3 | true |
68 > 60 true |
68 < 85 true |
true |
| 6 | true |
90 > 60 true |
90 < 85 false |
false |
On line 6, two of the three pieces are true, but one false makes the whole && expression false.
Reread 2.5.2 Requiring Both Conditions with AND if your answer differed.
Question 4 · Multiple choice
For which value of points does points > 50 && points % 2 == 0 evaluate to true?
51486450
Check your reasoning
C. 64 > 50 is true, and 64 % 2 is 0, so 64 % 2 == 0 is true. Both sides are true, so the && is true. (Recall from Topic 1.3 that % 2 gives 0 for an even number.)
- A is wrong:
51 > 50istrue, but51 % 2is1, so the second side isfalse. - B is wrong:
48is even, but48 > 50isfalse. - D is wrong:
50is even, but50 > 50isfalse; “greater than” does not include equal.
Reread 2.5.2 Requiring Both Conditions with AND if you chose differently.
2.5.3 Accepting Either Condition with OR
A museum lets children under 5 and adults 65 or older in for free. Here a visitor needs to pass at least one test, not both. Nobody is both under 5 and over 65, so && would let no one in free. Java needs a second way to combine conditions.
The OR operator, written || (two vertical bars; on most keyboards the bar is above the Enter key), combines two boolean values. The result is true when at least one of them is true, and false only when both are false. Think of a room with two doors: you can get in if either door is open.
a |
b |
a || b |
|---|---|---|
true |
true |
true |
true |
false |
true |
false |
true |
true |
false |
false |
false |
Look at the first row. In everyday speech, “or” sometimes means “one or the other, but not both,” as in “soup or salad comes with your meal.” Java’s || never means that. When both sides are true, || is true.
Key idea
a || b is true when a is true, b is true, or both are. It is false only when both sides are false.
Worked example: Free entry for young children and seniors
int age = 70;
boolean freeEntry = age < 5 || age >= 65;
System.out.println(freeEntry);
age = 30;
freeEntry = age < 5 || age >= 65;
System.out.println(freeEntry);| Line | age |
age < 5 |
age >= 65 |
|| result |
|---|---|---|---|---|
| 2 | 70 | false |
true |
true |
| 5 | 30 | false |
false |
false |
Output:
true
falseFor 70, one side is true, and that is enough. For 30, neither side is true, which is the only way || gives false.
To see the “both are true” row in action, here is a store that gives a discount to anyone with a coupon or a membership:
boolean hasCoupon = true;
boolean isMember = true;
System.out.println(hasCoupon || isMember);This prints true. A customer with both a coupon and a membership still gets the discount; having two reasons does not cancel it out.
Now vary the operands again. The pieces of an || can be any boolean expressions, including calls to the String method equals from Topic 1.15, which returns true when two strings hold the same text.
Worked example: Checking for either weekend day
String day = "Sun";
if (day.equals("Sat") || day.equals("Sun"))
{
System.out.println("Weekend hours: 10 to 4");
}
else
{
System.out.println("Weekday hours: 8 to 6");
}| Step | Expression | Value |
|---|---|---|
| 1 | day.equals("Sat") |
false |
| 2 | day.equals("Sun") |
true |
| 3 | false || true |
true |
The condition is true, so the if body runs:
Weekend hours: 10 to 4If day held "Wed", both calls would return false, the condition would be false, and the else body would print the weekday hours.
Watch out
Shortening the second comparison. In English you might say “if the day is 6 or 7,” so students write:
int day = 6;
if (day == 6 || 7)
{
System.out.println("Weekend");
}This does not compile. Java reports something like:
error: bad operand types for binary operator '||'
first type: boolean
second type: intBoth sides of || must be boolean values. The left side, day == 6, is a boolean. The right side is just the number 7, which is not true or false. Java does not fill in the missing day == for you. Write each comparison in full:
int day = 6;
if (day == 6 || day == 7)
{
System.out.println("Weekend");
}This prints Weekend. (Exact error wording can vary between Java versions.)
Watch out
Using && when the situation needs ||. English “and” can fool you. You might describe the museum rule as “children under 5 and seniors get in free,” and then write &&:
int age = 70;
if (age < 5 && age >= 65)
{
System.out.println("Free entry");
}
else
{
System.out.println("Pay full price");
}This compiles and prints Pay full price, even for a 70-year-old. For age equal to 70, age < 5 is false, so && is false. In fact, no number is both less than 5 and at least 65, so this condition is false for every age and nobody ever gets in free. Java gives no error, because the code is legal; it just does not mean what you intended. Before choosing an operator, ask: must one person pass both tests (&&), or is passing either test enough (||)? Here, either is enough, so the fix is age < 5 || age >= 65.
Pause and try
Question 5 · Tracing
What does this code print? Show the value of each side of the ||.
String weather = "snow";
int temp = 40;
if (weather.equals("rain") || temp < 32)
{
System.out.println("Stay inside.");
}
else
{
System.out.println("Go outside.");
}Check your reasoning
It prints Go outside.
| Step | Expression | Value |
|---|---|---|
| 1 | weather.equals("rain") |
false (the text is "snow") |
| 2 | temp < 32 |
false (40 is not below 32) |
| 3 | false || false |
false |
Both sides are false, the only case where || is false, so the else body runs. If you picked Stay inside., check that you compared "snow" with "rain", not with any bad weather.
Reread 2.5.3 Accepting Either Condition with OR if your answer differed.
Question 6 · Multiple choice
A ride closes when windSpeed (an int) is above 40 or when isRaining (a boolean) is true. Which expression is true exactly when the ride should close?
windSpeed > 40 && isRainingwindSpeed > 40 || isRainingwindSpeed || isRaining > 40!(windSpeed > 40) || isRaining
Check your reasoning
B. Either reason alone closes the ride, so the two conditions are joined with ||. windSpeed > 40 is a boolean, and isRaining already is one.
- A is wrong:
&&closes the ride only when it is windy and raining at the same time. A dry day with 50 mph wind would stay open. - C is wrong: it does not compile.
windSpeedis anint, not true or false, so it cannot be a side of||; andisRainingis aboolean, which cannot be compared with40using>. The comparison belongs next towindSpeed, as in choice B. - D is wrong:
!(windSpeed > 40)istruewhen the wind is not above 40, so this closes the ride on calm days.
Reread 2.5.3 Accepting Either Condition with OR if you chose differently.
2.5.4 Order of Evaluation
Once a condition has more than one logical operator, a question comes up that a single operator never raised. What does this mean?
a || b && c
Does Java combine a || b first and then && c? Or b && c first and then a ||? The two orders can give different answers, so Java needs a rule. You met the same problem with arithmetic in Topic 1.3: 2 + 3 * 4 is 14, not 20, because multiplication has higher precedence (it is done first) than addition.
Logical operators have their own precedence:
!(NOT) first&&(AND) next||(OR) last
So in a || b && c, the && happens before the ||, as if you had written a || (b && c). A memory hook: AND is like multiplication and OR is like addition, so AND goes first.
These operators also fit into the bigger order you already know. ! applies to the single value right after it, before any arithmetic or comparison, which is why !battery > 20 failed in 2.5.1. Arithmetic and comparisons such as <, >=, and == all happen before && and ||. That is why age >= 13 && age <= 19 works without parentheses: both comparisons become boolean values first, and only then does && combine them.
| Order | Operators |
|---|---|
| 1 | parentheses ( ) |
| 2 | ! |
| 3 | * / %, then + - |
| 4 | < > <= >=, then == != |
| 5 | && |
| 6 | || |
Parentheses beat everything, so whenever you want a different order, or just want the order to be obvious to a reader, add them.
Key idea
Comparisons are evaluated before logical operators. Among the logical operators, ! goes first, then &&, then ||.
Parentheses override the order.
Precedence tells you how an expression is grouped: which operands each operator combines, as if Java had added invisible parentheses. Once you know the grouping, you can find the value by working out the innermost groups first, as the tables below do. (In 2.5.5 you will see that Java sometimes skips part of an expression. That never changes the value; it only matters when the skipped part would have crashed.)
Worked example: The same operators, with and without parentheses
boolean a = true;
boolean b = false;
boolean c = false;
System.out.println(a || b && c);
System.out.println((a || b) && c);Line 4, a || b && c, follows the precedence rule: && first.
| Step | Expression | Value |
|---|---|---|
| 1 | b && c → false && false |
false |
| 2 | a || false → true || false |
true |
Line 5, (a || b) && c, uses parentheses to force || first.
| Step | Expression | Value |
|---|---|---|
| 1 | (a || b) → true || false |
true |
| 2 | true && c → true && false |
false |
Output:
true
falseThe same three variables and the same two operators give different results. The only difference is which operator runs first.
Now add ! and some comparisons, and compare ! on one value with ! on a whole parenthesized expression.
Worked example: NOT, comparisons, AND, and OR together
int x = 4;
boolean flag = false;
System.out.println(!flag && x > 5 || x == 4);
System.out.println(!(flag && x > 5 || x == 4));Line 3 has no extra parentheses, so every rule from the table applies. x is 4 and flag is false.
| Step | What runs | Expression becomes |
|---|---|---|
| 1 | !flag (NOT first) |
true && x > 5 || x == 4 |
| 2 | comparisons | true && false || true |
| 3 | && |
false || true |
| 4 | || |
true |
Line 4 puts the whole expression in parentheses with ! outside, so the inside is finished first and ! flips the final result.
| Step | What runs | Expression becomes |
|---|---|---|
| 1 | comparisons | !(false && false || true) |
| 2 | && |
!(false || true) |
| 3 | || |
!(true) |
| 4 | ! |
false |
Output:
true
falseOn line 3, ! flipped only flag. On line 4, it flipped the whole result. Where the parentheses go decides what ! applies to.
Watch out
Writing a condition in the order you would say it. A theater gives free popcorn to members or seniors, but only on Tuesdays. A student writes:
boolean isMember = true;
int age = 30;
boolean isTuesday = false;
if (isMember || age >= 65 && isTuesday)
{
System.out.println("Free popcorn!");
}
else
{
System.out.println("Popcorn is $5.");
}It is Wednesday (isTuesday is false), yet this prints Free popcorn!. Because && runs before ||, Java reads the condition as isMember || (age >= 65 && isTuesday). That says “members any day, or seniors on Tuesday.” Step by step: age >= 65 && isTuesday is false && false, which is false; then isMember || false is true || false, which is true.
The intended meaning is “(member or senior) and Tuesday,” so the || must happen first. Add parentheses:
boolean isMember = true;
int age = 30;
boolean isTuesday = false;
if ((isMember || age >= 65) && isTuesday)
{
System.out.println("Free popcorn!");
}
else
{
System.out.println("Popcorn is $5.");
}Now (isMember || age >= 65) is true, and true && isTuesday is true && false, which is false. It prints Popcorn is $5. Whenever a condition mixes && and ||, check which one you need to happen first, and use parentheses if it is the ||.
Pause and try
Question 7 · Tracing
What does this code print? Show the order in which the operators run on each line.
boolean p = false;
boolean q = true;
boolean r = true;
System.out.println(p && q || r);
System.out.println(p && (q || r));
System.out.println(!p || q && !r);Check your reasoning
It prints:
true
false
true- Line 4,
p && q || r:&&first.false && trueisfalse. Thenfalse || trueistrue. - Line 5,
p && (q || r): parentheses first.true || trueistrue. Thenfalse && trueisfalse. - Line 6,
!p || q && !r:!first, so!pistrueand!risfalse. Then&&:q && falseistrue && false, which isfalse. Then||:true || falseistrue.
If you got false on line 4, you grouped it as p && (q || r). Java uses that grouping only when parentheses ask for it, as on line 5.
Reread 2.5.4 Order of Evaluation if your answer differed.
Question 8 · Multiple choice
Which choice adds parentheses that show exactly how Java groups a || b && !c, where a, b, and c are boolean variables?
(a || b) && (!c)a || (b && (!c))!(a || b && c)(a || b) && !c
Check your reasoning
B. ! goes first and applies only to c. Then && combines b with !c. Then || combines a with that result.
- A is wrong: it makes
||happen before&&, which is the reverse of Java’s order. - C is wrong: it moves
!so it flips the whole expression. In the original,!is directly in front ofcand applies only toc. - D is wrong for the same reason as A: the parentheses force
||first.
Reread 2.5.4 Order of Evaluation if you chose differently.
2.5.5 Short-Circuit Evaluation
A grade program finds a student’s average by dividing the total of their scores by how many scores there are. Early in the term a new student has no scores yet, so the count is 0. From Topic 1.3, integer division by zero crashes the program with an ArithmeticException. The program should check “there is at least one score and the average is at least 80,” but the second part is exactly the part that can crash.
In Topic 2.4 you saw that an inner if is checked only when the outer if’s condition is true, so you could protect the division by nesting it inside if (count > 0). It turns out && already protects it on its own, because of how Java evaluates && and ||.
Look back at the AND table. If the left side of && is false, the result is false no matter what the right side is. Java notices this. It evaluates the left side first, and if that side alone decides the answer, it does not evaluate the right side at all. The same is true for ||: if the left side is true, the result is true no matter what, so the right side is skipped.
| Operator | Left side is | Result | Right side |
|---|---|---|---|
&& |
false |
false |
skipped |
&& |
true |
depends on the right | evaluated |
|| |
true |
true |
skipped |
|| |
false |
depends on the right | evaluated |
Skipping the right side when the left side already decides the result is called short-circuit evaluation. It is like a teacher who checks whether homework was turned in before grading it: if there is no homework, there is nothing to grade, so the second step never happens.
Usually skipping the right side only saves a little time. It matters when the right side would crash, because then a check on the left can act as a guard: a condition placed first so that the risky part runs only when it is safe.
Key idea
Java evaluates the left side of && or || first. If the left side of && is false, or the left side of || is
true, the right side is never evaluated.
When an expression mixes operators, the “sides” are the groups that precedence makes (2.5.4). In a || b && c, the right side of || is the whole group b && c. If a is true, Java skips that entire group.
Worked example: A guard before a division with AND
int total = 0;
int count = 0;
if (count > 0 && total / count >= 80)
{
System.out.println("Honor roll");
}
else
{
System.out.println("No honor roll yet");
}| Step | Expression | Value | Notes |
|---|---|---|---|
| 1 | count > 0 → 0 > 0 |
false |
left side |
| 2 | false && ... |
false |
right side, total / count >= 80, is skipped |
| 3 | condition is false |
run the else body |
Output:
No honor roll yetThe division total / count would be 0 / 0, which crashes, but it never runs. If count held 4 and total held 340, the left side would be true, Java would evaluate the right side (340 / 4 is 85, and 85 >= 80 is true), and the program would print Honor roll.
Now vary the operator. With ||, the guard is written the other way around: the left side checks for the dangerous case and is true when it happens.
Worked example: A guard before a division with OR
int total = 0;
int count = 0;
if (count == 0 || total / count < 60)
{
System.out.println("Check in with your teacher");
}
else
{
System.out.println("On track");
}| Step | Expression | Value | Notes |
|---|---|---|---|
| 1 | count == 0 → 0 == 0 |
true |
left side |
| 2 | true || ... |
true |
right side, total / count < 60, is skipped |
| 3 | condition is true |
run the if body |
Output:
Check in with your teacherAgain the division never runs. A student with no scores yet is sent to check in, and Java does not need the average to decide that.
Watch out
Putting the risky part first. Short-circuiting only skips the right side. If you write the guard second, the division runs before the guard is ever checked:
int total = 0;
int count = 0;
if (total / count >= 80 && count > 0)
{
System.out.println("Honor roll");
}
else
{
System.out.println("No honor roll yet");
}Nothing prints. The program crashes on line 3 with:
Exception in thread "main" java.lang.ArithmeticException: / by zeroJava evaluates the left side of && first, and that left side is now total / count >= 80, which divides by zero. The count > 0 check comes too late to help. The fix is to swap the two sides so the guard is on the left: count > 0 && total / count >= 80. Which side the guard is on decides whether the program crashes.
Pause and try
Question 9 · Tracing
What does this code print? Is the substring call ever run?
String word = "cat";
if (word.length() > 3 && word.substring(3, 4).equals("s"))
{
System.out.println("Fourth letter is s");
}
else
{
System.out.println("No fourth s");
}Check your reasoning
It prints No fourth s, and substring is never called.
| Step | Expression | Value |
|---|---|---|
| 1 | word.length() > 3 → 3 > 3 |
false |
| 2 | false && ... |
false; the right side is skipped |
| 3 | condition is false |
run the else body |
"cat" has indexes 0 to 2, so word.substring(3, 4) would ask for a character past the end and throw a StringIndexOutOfBoundsException (Topic 1.15). The length check on the left is a guard: because it is false, short-circuit evaluation skips the risky call.
Reread 2.5.5 Short-Circuit Evaluation if your answer differed.
Question 10 · Multiple choice
n is an int that holds 0. Which expression crashes with an ArithmeticException when Java evaluates it?
n != 0 && 10 / n > 1n == 0 || 10 / n > 110 / n > 1 && n != 0n > 0 && 10 / n > 1
Check your reasoning
C. Java always evaluates the left side first, and in C the left side is the division 10 / 0, which crashes before n != 0 is checked.
- A is wrong:
n != 0isfalse, so&&short-circuits tofalseand the division is skipped. - B is wrong:
n == 0istrue, so||short-circuits totrueand the division is skipped. - D is wrong:
n > 0isfalse, so&&short-circuits tofalseand the division is skipped.
Reread 2.5.5 Short-Circuit Evaluation and its Watch Out if you chose differently.
Putting it together
This program decides whether a child can ride a roller coaster. The ride is open when it is not raining and the wind is under 30 mph. A rider must be at least 48 inches tall and must be 12 or older or riding with an adult. Before reading the trace, predict the four lines of output.
Worked example: Roller coaster check
public class RideCheck
{
public static void main(String[] args)
{
int heightInches = 50;
int age = 11;
boolean withAdult = true;
boolean isRaining = false;
int windSpeed = 25;
boolean rideOpen = !isRaining && windSpeed < 30;
boolean tallEnough = heightInches >= 48;
boolean oldEnough = age >= 12 || withAdult;
System.out.println("Ride open: " + rideOpen);
System.out.println("Tall enough: " + tallEnough);
System.out.println("Old enough: " + oldEnough);
if (!rideOpen)
{
System.out.println("Sorry, the ride is closed.");
}
else if (tallEnough && oldEnough)
{
System.out.println("Enjoy the ride!");
}
else
{
System.out.println("Not this time.");
}
}
}Lines 5–9 set the situation: a child 50 inches tall, age 11, with an adult, on a dry day with 25 mph wind. Lines 11–13 each store the result of a Boolean expression in a variable with a clear name, so the if statement later reads almost like English.
| Line | Expression | Steps | Result |
|---|---|---|---|
| 11 | !isRaining && windSpeed < 30 |
!false is true; 25 < 30 is true; true && true |
true |
| 12 | heightInches >= 48 |
50 >= 48 |
true |
| 13 | age >= 12 || withAdult |
11 >= 12 is false; false || true |
true |
Lines 15–17 print each result. String concatenation (Topic 1.15) turns a boolean into the text true or false.
Lines 19–30 are an if-else-if chain from Topic 2.4. The first condition, !rideOpen, is !true, which is false, so Java moves on. The second, tallEnough && oldEnough, is true && true, which is true, so its body runs and the rest of the chain is skipped.
Ride open: true
Tall enough: true
Old enough: true
Enjoy the ride!Two details are worth a second look. On line 13, the 11-year-old is too young on age alone, but || needs only one true, and withAdult supplies it. Because || evaluated its left side first and found it false, Java did evaluate the right side here; short-circuiting happens only when the left side settles the answer.
Now suppose it starts raining. Here are just the lines that matter, with isRaining set to true:
boolean isRaining = true;
int windSpeed = 25;
boolean rideOpen = !isRaining && windSpeed < 30;
System.out.println("Ride open: " + rideOpen);
if (!rideOpen)
{
System.out.println("Sorry, the ride is closed.");
}Ride open: false
Sorry, the ride is closed.!isRaining is now false, so the && on line 3 short-circuits: the wind check is skipped and rideOpen is false. In the full program, the first branch of the chain, !rideOpen, would be true, so the closed message prints and the height and age checks never matter.
Vocabulary
| Term | Definition | Example |
|---|---|---|
| logical operator | An operator that works on boolean values and produces a boolean value: !, &&, or || |
isOpen && hasTicket |
| NOT operator | !, written before one boolean value; produces the opposite value |
!isRaining |
| AND operator | &&; true only when both sides are true |
age >= 13 && age <= 19 |
| compound Boolean expression | A Boolean expression built from smaller Boolean expressions joined by logical operators; evaluates to true or false |
age < 5 || age >= 65 |
| OR operator | ||; true when at least one side is true |
hasCoupon || isMember |
| precedence | The order in which operators are evaluated; for logical operators, ! then && then || |
a || b && c means a || (b && c) |
| short-circuit evaluation | Skipping the right side of && or || because the left side already decides the result |
count > 0 && total / count > 80 |
| guard | A condition placed on the left so the risky right side runs only when it is safe | count > 0 in the line above |
Chapter summary
!flips aboolean:!aistrueexactly whenaisfalse. To flip a comparison, wrap it in parentheses:!(battery > 20).a && bistrueonly when both sides aretrue;a || bistruewhen at least one side istrue, including when both are. Every compound Boolean expression evaluates to a singleboolean.- Each side of
&&and||must be a completebooleanexpression: write13 <= age && age <= 19, not13 <= age <= 19, andday == 6 || day == 7, notday == 6 || 7. - Comparisons happen before logical operators, and among logical operators
!comes first, then&&, then||. Use parentheses to change the order. - Java evaluates the left side of
&&and||first and skips the right side when the left side decides the result (falsefor&&,truefor||). Put a guard on the left to protect a risky right side.
Review questions
Question 11 · Multiple choice
What does this code print?
int boxes = 0;
int items = 24;
boolean ok = boxes != 0 && items / boxes > 5 || items > 20;
System.out.println(ok);truefalse- Nothing; it crashes with an
ArithmeticException - Nothing; it does not compile
Check your reasoning
A. By precedence, && runs before ||, so Java groups the expression as (boxes != 0 && items / boxes > 5) || items > 20.
boxes != 0is0 != 0, which isfalse.- The
&&short-circuits: its right side,items / boxes > 5, is skipped, and the&&part isfalse. - The
||now hasfalseon its left, so Java evaluates its right side:24 > 20istrue. false || trueistrue.
- B is wrong: it stops after the
&&part. That part isfalse, but it is only the left side of||, and the right side of||istrue. - C is wrong: the division never runs, because the
&&short-circuits whenboxes != 0isfalse. - D is wrong: every operand of
&&and||is a completebooleanexpression, so the code compiles.
Reread 2.5.4 Order of Evaluation and 2.5.5 Short-Circuit Evaluation if you chose differently.
Question 12 · Tracing
What does this code print? For each condition in the chain, show whether it is true or false.
int score = 84;
int absences = 5;
boolean extraCredit = true;
String grade;
if (score >= 90 || score >= 88 && extraCredit)
{
grade = "A";
}
else if (score >= 80 && !(absences > 3))
{
grade = "B";
}
else if (score >= 70 || extraCredit)
{
grade = "C";
}
else
{
grade = "D";
}
System.out.println("Grade: " + grade);Check your reasoning
It prints Grade: C.
| Condition | Steps | Value |
|---|---|---|
score >= 90 || score >= 88 && extraCredit |
Grouped as score >= 90 || (score >= 88 && extraCredit). 84 >= 90 is false, so Java evaluates the group on the right: 84 >= 88 is false, so the && is false. false || false is false. |
false |
score >= 80 && !(absences > 3) |
84 >= 80 is true. 5 > 3 is true, so !(true) is false. true && false is false. |
false |
score >= 70 || extraCredit |
84 >= 70 is true, so || short-circuits to true. |
true |
The third condition is the first true one, so grade becomes "C" and the else is skipped (Topic 2.4). If you answered B, you probably missed the !: absences > 3 is true, and ! flips it to false, so too many absences block the B.
Reread 2.5.1 Reversing a Condition with NOT and 2.5.4 Order of Evaluation if your answer differed.
Question 13 · Debugging
This code should print Valid month only when month is from 1 through 12. With month equal to 15, it prints Valid month. Find the error, explain why every number passes, and correct the condition.
int month = 15;
if (month >= 1 || month <= 12)
{
System.out.println("Valid month");
}
else
{
System.out.println("Invalid month");
}Check your reasoning
The error is on line 2: || should be &&. A valid month must pass both tests, at least 1 and at most 12. With ||, passing either test is enough. For 15, month >= 1 is true, so the || is true (and short-circuits). In fact every whole number is either at least 1 or at most 12 (numbers below 1 pass the second test), so the condition is true for every value and Invalid month can never print. The code compiles, so only testing reveals the bug.
Corrected code:
int month = 15;
if (month >= 1 && month <= 12)
{
System.out.println("Valid month");
}
else
{
System.out.println("Invalid month");
}Now 15 >= 1 is true but 15 <= 12 is false, so true && false is false, and it prints Invalid month.
Reread 2.5.2 Requiring Both Conditions with AND and the second Watch Out in 2.5.3 Accepting Either Condition with OR if you missed it.
Question 14 · Short answer
count holds 0. Both segments below run without crashing. Explain why each one is safe, and say what feature of Java makes the second one safe.
if (count > 0)
{
if (total / count > 10)
{
System.out.println("High average");
}
}if (count > 0 && total / count > 10)
{
System.out.println("High average");
}Check your reasoning
Model answer: In the first segment, the outer condition count > 0 is false, so Java skips the whole body of the outer if, including the inner if; its division is never evaluated (Topic 2.4). In the second segment, Java evaluates the left side of && first. count > 0 is false, which already makes the whole && expression false, so short-circuit evaluation skips the right side and the division never runs. Neither segment prints anything. The second does in one condition what the first does with nesting, but only because the guard count > 0 is on the left of &&.
A complete answer must:
- say that the division
total / countis never evaluated in either segment, - explain that the inner
ifruns only when the outer condition istrue, and - name short-circuit evaluation:
&&skips its right side when its left side isfalse.
Reread 2.5.5 Short-Circuit Evaluation if your answer differed.
Question 15 · Multiple choice
a and b are boolean variables. a && b evaluates to false, and a || b evaluates to true. What must be the case?
- Both
aandbaretrue. - Both
aandbarefalse. - Exactly one of
aandbistrue. aistrueandbisfalse; no other combination works.
Check your reasoning
C. a || b is true, so at least one of them is true. a && b is false, so they are not both true. The only combinations left are true/false and false/true: exactly one is true.
- A is wrong: if both were
true,a && bwould betrue. - B is wrong: if both were
false,a || bwould befalse. - D is wrong:
abeingfalseandbbeingtruealso givesfalsefor&&andtruefor||. Neither operator cares which side holds thetrue.
Reread 2.5.2 Requiring Both Conditions with AND and 2.5.3 Accepting Either Condition with OR if you chose differently.
Reflection
Check each statement. If the answer is “not yet,” reread the linked subsection.
- I can use ! to flip a boolean value or a comparison in parentheses. Reread
- I can use && to require two conditions and write a range check correctly. Reread
- I can use || to accept either condition, and I know it is true when both sides are true. Reread
- I can evaluate an expression that mixes !, &&, and || in the right order, and use parentheses to change it. Reread
- I can explain when Java skips the right side of && or || and use a guard to prevent a crash. Reread