Advanced Java/Bitwise Operators

Short-Circuit Evaluation

edit

It should be noted that, when given a boolean logical operator, the JVM checks as few operands as possible, from left to right. For example, if the first operator of an OR expression is true, then the expression will be true no matter what the second operand is. Short-circuiting applies to the AND and OR operators.

This is called short-circuit evalution and is important if the second operand is a method call. Consider the following methods:

public boolean showFalse() {
    System.out.println("False!");
    return false;
}

public void go() {
    System.out.println("Foo!");
    if(true && showFalse()) {
        // huzzah
    }
    System.out.println("Bar!");
}

If the go() method is called, the output is

Foo!
False!
Bar!

Why? The JVM hits the if statement and looks at the first operand — here, the true literal. The expression could still go either way: for an AND to be true, both operands must be true. So the JVM checks the second operand; since it's a method call, the method is called in its entirety.

What if the first operand was the false literal?

public void go() {
    System.out.println("Foo!");
    if(false && showFalse()) {
        //huzzah
    }
    System.out.println("Bar!");
}

The JVM sees that the first operand is false and immediately evaluates the entire AND expression as false. (Remember, an AND expression is only true if both operands are true.) Because the second operand is never checked, the method is never called, and the output is

Foo!
Bar!

Long-Circuit Evaluation

edit

Usually, short-circuit evaluation is a good thing, because it saves running time. But if the second operand is a method call that changes something before returning a value, you might want to force the method to run no matter what. To do this, use the long-circuit logical operators. They're the same as the bitwise operators, but they operate logically when applied to booleans. They're exactly the same as the short-circuit boolean operators, only not doubled.

Short-circuit Long-circuit
AND && &
OR || |
XOR none ^

Note that there is no short-circuit form of the XOR operator, because, mathematically, it always needs to evaluate both its arguments to compute its result.

If you use a bitwise operator in a boolean expression, both operands are always evaluated. Consider the above code again. If the go() method is rewritten:

public void go() {
    System.out.println("Foo!");
    if(false & showFalse()) {
        //huzzah
    }
    System.out.println("Bar!");
}

Then the output will be:

Foo!
False!
Bar!

Because the showFalse() method will be called even though the first operand (the false literal) alone determines the result of the entire expression.

Bitwise Operations

edit

The other use of the bitwise operators is manipulating individual bits in an int. (Note that the operands can be any integral type; but if it is a type smaller than int, it will be promoted to an int type, and the result will be int.)

For the purposes of this section, we'll define the following variables:

int a =  12; // 0000 0000 0000 0000 0000 0000 0000 1100
int b =   5; // 0000 0000 0000 0000 0000 0000 0000 0101
int x = -37; // 1111 1111 1111 1111 1111 1111 1101 1011
The Bitwise Operators
Operator Name
~ Bitwise NOT
& Bitwise AND
| Bitwise OR
^ Bitwise XOR
<< Left-Shift
>> Right-Shift (Keep bits)
>>> Right-Shift (Force bits)

Bitwise NOT

edit

The bitwise NOT is a unary operator (it takes only one operand) that flips every bit in its operand.

int c = ~b; // 1111 1111 1111 1111 1111 1111 1111 1010 = -6

Bitwise AND

edit

The result of a bitwise AND has on-bits (ones) only where both operands has an on-bit.

int d = a & b; //  ...0000 1100
               //& ...0000 0101
               //= ...0000 0100 = 4;

Bitwise OR

edit

The result of a bitwise OR has on-bits where either (or both) of its operands has an on-bit.

int e = a | b; //  ...0000 1100
               //| ...0000 0101
               //= ...0000 1101 = 13

Bitwise XOR

edit

The result of a bitwise XOR (eXclusive-OR) has on-bits where one and only one of its operands has an on-bit.

int f = a ^ b; //  ...0000 1100
               //^ ...0000 0101
               //= ...0000 1001 = 9

Left Shift

edit

The left-shift operator shifts the bits of the first operand left by the number of places specified by the second operand. Bits shoved off the left side are lost; empty bits on the right are filled in with zeros.

int g = a << 2; // ...0000 1100
                // ...0011 0000 = 48

Right Shift (Keep)

edit

The right-shift operator (keep bits) shifts the bits of the first operand right by the number of places specified by the second operand. Bits shoved off the right side are lost; bits on the left side are the same as the original left-most bit (the "sign bit").

int h = x >> 2; // 1111 .... 1101 1011
                // 1111 .... 1111 0110 = -10
int i = b >> 2; // 0000 .... 0000 0101
                // 0000 .... 0000 0001 = 1

Right Shift (Force)

edit

The right-shift operator (force bits) is the same as the right-shift (keep) operator. However, the new bits on the left are always set to zero.

int j = x >>> 2; // 1111 .... 1101 1011
                 // 0011 .... 1111 0110


Project: Advanced Java
Previous: Declaring float and long Literals — Advanced Java/Bitwise Operators — Next: java.util.List