liveBook · Manning

Bit shifting

As explained in 100 Java Mistakes and How to Avoid Them

A bitwise shift operator moves the binary representation of an integer left or right by a specified number of bit positions.

Bit shifting treats an integer as a bit vector, moving its representation left or right. It supports compact packed values, bit flags, masks, and fast low-level arithmetic, but small Java expression details can radically change the result. section 4.12

Addition binds before shifting

Do not assume a shift binds more tightly than addition. `lo << 16 + hi` is evaluated as `lo << (16 + hi)`, not `(lo << 16) + hi`. The compiler accepts both forms, so a packing expression or handwritten `hashCode()` can silently compute an unexpected value. In a hash calculation, a late left shift can wipe out low-order bits and produce poor hash distribution, harming `HashMap` performance. section 2.1.1

Parenthesize mixed addition-and-shift expressions to state the intended grouping, then verify the arithmetic rather than merely silencing an analyzer. A buffer-capacity expression intended to add 25% can instead parse as `(BLOCK_SIZE + BLOCK_SIZE) >> 2`, yielding half the block size. Parentheses that preserve that existing parse remove the warning without repairing the intent. section 2.1.1

int value;

void applyMask(int keepBits) {
  value &= (1 << keepBits) - 1;
}

This mask idiom preserves the least-significant `keepBits` bits for ordinary counts, but exposes a boundary case: shifting an `int` by 32 shifts by zero instead. section 4.12

Check these Java-specific shift hazards:

  • For `int`, Java uses the shift amount modulo 32; for `long`, it uses modulo 64. Thus `1 << 32` is `1 << 0`, so `(1 << 32) - 1` becomes zero rather than an all-bits mask. section 4.12
  • The shift result type follows the left operand. When constructing a `long` bit mask, a left operand written as `1` is an `int`; make the operand explicitly long when a long shift result is required. section 4.12
  • Treat analyzer diagnostics as prompts to inspect intent. Tools commonly flag an `int` shifted by 32 and mixed addition/shift expressions; IDE plugins, built-in inspections, and build-integrated analyzers can surface such cases. section 1.3.2 section 2.1.1

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains precedence, modulo shift counts, result typing, and concrete masking corner cases.
Examples
Uses value packing, a handwritten hashCode, buffer sizing, a least-significant-bit mask, and a long field bit setter.
What it assumes
Assumes familiarity with Java integer expressions while explaining shift-specific precedence and boundary behavior.
What you can do after
Diagnose/debug with it by checking grouping, shift-count boundaries, and left-operand types in Java expressions.
How it connects
Connects shifts with operator precedence, hashCode, HashMap, bit masks, static analysis, and integer types.

Also explained in

Compare how 2 books explain bit shifting →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.