null
reference always returns false
.
System.out.print(null instanceof Object); // false Object noObjectHere = null; System.out.print(noObjectHere instanceof String); // false
The preceding examples both print false
. It almost doesn't matter what the right side of the expression is. We say “almost” because there are exceptions. This example does not compile, since null
is used on the right side of the instanceof
operator:
System.out.print(null instanceof null); // DOES NOT COMPILE
instanceof
operator, there's a lot more coming! In Chapter 3, we introduce pattern matching with the instanceof
operator, which was officially added in Java 16. In Chapter 7, “Beyond Classes,” we introduce polymorphism in much more detail and show how to apply these rules to interfaces.
Logical Operators
If you have studied computer science, you may have already come across logical operators before. If not, no need to panic—we'll be covering them in detail in this section.
The logical operators, (&
), (|
), and (^
), may be applied to both numeric and boolean
data types; they are listed in Table 2.9. When they're applied to boolean
data types, they're referred to as logical operators. Alternatively, when they're applied to numeric data types, they're referred to as bitwise operators, as they perform bitwise comparisons of the bits that compose the number. For the exam, though, you don't need to know anything about numeric bitwise comparisons, so we'll leave that educational aspect to other books.
TABLE 2.9 Logical operators
Operator | Example | Description |
---|---|---|
Logical AND |
a & b
|
Value is true only if both values are true .
|
Logical inclusive OR |
c | d
|
Value is true if at least one of the values is true .
|
Logical exclusive OR |
e ^ f
|
Value is true only if one value is true and the other is false .
|
You should familiarize yourself with the truth tables in Figure 2.2, where x
and y
are assumed to be boolean
data types.
FIGURE 2.2 The logical truth tables for &
, |
, and ^
Here are some tips to help you remember this table:
AND is only true if both operands are true.
Inclusive OR is only false if both operands are false.
Exclusive OR is only true if the operands are different.
Let's take a look at some examples:
boolean eyesClosed = true; boolean breathingSlowly = true; boolean resting = eyesClosed | breathingSlowly; boolean asleep = eyesClosed & breathingSlowly; boolean awake = eyesClosed ^ breathingSlowly; System.out.println(resting); // true System.out.println(asleep); // true System.out.println(awake); // false
You should try these out yourself, changing the values of eyesClosed
and breathingSlowly
and studying the results.
Conditional Operators
Next, we present the conditional operators, &&
and ||
, in Table 2.10.
TABLE 2.10 Conditional operators
Operator | Example | Description |
---|---|---|
Conditional AND |
a && b
|
Value is true only if both values are true . If the left side is false , then the right side will not be evaluated.
|
Conditional OR |
c || d
|
Value is true if at least one of the values is true . If the left side is true , then the right side will not be evaluated.
|
The conditional operators, often called short-circuit operators, are nearly identical to the logical operators, &
and |
, except that the right side of the expression may never be evaluated if the final result can be determined by the left side of the expression. For example, consider the following statement:
int hour = 10; boolean zooOpen = true || (hour < 4); System.out.println(zooOpen); // true
Referring to the truth tables, the value zooOpen
can be false
only if both sides of the expression are false
. Since we know the left side is true
, there's no need to evaluate the right side, since no value of hour
will ever make this code print false
. In other words, hour
could have been -10
or 892
; the output would have been the same. Try it yourself with different values for hour
!
Avoiding a NullPointerException
A more common example of where conditional operators are used is checking for null
objects before performing an operation. In the following example, if duck
is null
, the program will throw a NullPointerException
at runtime:
if(duck!=null & duck.getAge()<5) { // Could throw a NullPointerException // Do something }
The issue is that the logical AND (&
) operator evaluates both sides of the expression. We could add a second if
statement, but this could get unwieldy if we have a lot of variables to check. An easy-to-read solution is to use the conditional AND operator (&&
):
if(duck!=null && duck.getAge()<5) { // Do something }
In this example, if duck
is null
, the conditional prevents a NullPointerException
from ever being thrown, since the evaluation of duck.getAge() < 5
is never reached.