Next: Defining methods. Up: Logic and class members. Previous: None.


Logical operators

Textbook: Section 4.2

Sometimes you want to compute with booleans using logical operations like AND. Java provides these: && for AND, || for OR, and ! for NOT.

For example, you might have the following:

while(i * i <= num && num % i != 0) i++;
Here we're saying to continue incrementing i as long as both i*i<=n and also n%i!=0.

This particular expression is part of my longer program to test whether a number is prime.

import csbsju.cs160.*;

public class PrimeTest {
    public static void run() {
        IO.print("test what? ");
        int num = IO.readInt();

        int i = 2;
        while(i * i <= num && num % i != 0) i++;
        IO.println(i * i > num);
    }
}

Short circuit evaluation

Java uses short-circuit evaluation to take the AND or OR of two expressions. That is, the computer will first evaluate the first expression, and then it will look at the second expression only if it needs to.

Usually this doesn't matter. But it's convenient when the second expression might cause an error. Consider the following.

i == 0 || n / i == 0
The second expression is erroneous when i holds 0, as then the computer would divide by 0. But, because of short-circuit evaluation, the computer will never reach that point: If i holds 0, the first expression is true, and so the computer automatically knows that the entire expression is true. There's no reason to try the division!

Precedence order

How do these operators fit into the hierarchy? Here's an updated table of our operators.

unary +, unary -highest precedence
!, ++, --
*, /, %
binary +, binary -
<, >, <=, >=
==, !=
&&
||
=, +=, -=, *=, /=, %=lowest precedence

Notice that AND and OR fall very low in the hierarchy - which is good, since generally we want the comparison operators to be above them. They're at different levels; all ANDs are performed before the ORs.

But also notice how high the NOT operator is! This is a horrible design that dates from the days of C, and which Java kept just in order not to confuse old C programmers. You almost never want NOT to be so important.

As a result, you should always parenthesize whenever you use the NOT operator. The default precedence is basically never correct.

de Morgan's laws

Even better is to try to get rid of the NOT operators. Using the NOT operator is not a little confusing, since not many people can avoid being confused by negated terms. This reminds me of the irritating, poorly worded true/false test questions: True or false? The AND operator is not above NOT in the precedence hierarchy.

Since Java includes the full complement of comparisons, you can always push NOT into a comparison: Instead of !(i < 0), write i >= 0.

But when the NOT is over an AND, like the following, you need to apply de Morgan's law.

!(i == 0 || n / i == 0)
De Morgan's Laws are the following:
NOT (X AND Y) = (NOT X) OR (NOT Y)
NOT (X OR Y) = (NOT X) AND (NOT Y)
That is, a NOT distributes into an AND or an OR, flipping the AND into an OR or the OR into an AND.

When we apply de Morgan's law to our example, we get this instead.

!(i == 0) && !(n / i == 0)
And of course from here we can distribute the NOTs into the comparisons, to get rid of all the NOT operators.
i != 0 && n / i != 0


Next: Defining methods. Up: Logic and class members. Previous: None.