Bitwise operators
Operating on individual bits. Rarer than it used to be, still occasionally exactly right.
| Operator | Meaning |
|---|---|
& |
AND, 1 where both bits are 1 |
\| |
OR. 1 where either is 1 |
^ |
XOR, 1 where exactly one is 1 |
~ |
NOT, flips every bit |
<< |
left shift |
>> |
arithmetic right shift, keeps the sign |
>>> |
logical right shift, fills with zero |
They work on integral types. Operands narrower than int are promoted to int first, which is why byte b = ~b; will not compile without a cast.
Flags
The main everyday use. Give each option a bit:
static final int READ = 1; // 0001
static final int WRITE = 1 << 1; // 0010
static final int EXECUTE = 1 << 2; // 0100
int perms = READ | WRITE; // set
boolean canWrite = (perms & WRITE) != 0; // test
perms |= EXECUTE; // add
perms &= ~WRITE; // remove
perms ^= READ; // toggle
Note != 0 on the test. perms & WRITE yields 2, not 1, so comparing to 1 fails. Comparing against the flag itself also works: (perms & WRITE) == WRITE.
In modern code an EnumSet is usually clearer and just as fast. Bit flags remain right when the value crosses a boundary you do not control, a file format, a protocol, a native API.
Shifts
x << n multiplies by 2ⁿ; x >> n divides by 2ⁿ, rounding toward negative infinity. Do not write shifts for arithmetic: the compiler optimises * 2 perfectly well and << 1 only obscures the intent.
The difference between >> and >>> matters for negative numbers. -8 >> 1 is -4, sign preserved. -8 >>> 1 is 2147483644, because the sign bit is filled with zero. Use >>> when the value is a bit pattern rather than a number.
Shift counts are taken modulo 32 for int and 64 for long, so x << 32 is x, not zero. This surprises people.
& and && are different
& and | on booleans work, but always evaluate both sides. && and || short-circuit. That matters when the right side would throw:
if (s != null && s.length() > 0) // safe
if (s != null & s.length() > 0) // throws on null
Use the doubled forms for logic. The single ones are for bits.
Useful idioms
(n & 1) == 0 // even
n & (n - 1) // clears the lowest set bit; zero means power of two
Integer.bitCount(n) // count the set bits
Integer.toBinaryString(n)