liveBook · Manning

Bit operation

As explained in 100 Java Mistakes and How to Avoid Them

The bitwise XOR operator computes a bit-by-bit exclusive disjunction of integer operands.

Bit operations treat integer values as bit vectors. They support masks, packed flags, byte composition, shifts, and low-level checks, but compact expressions can conceal precedence, signedness, and type-conversion errors. Prefer small, named operations over clever inline formulas. section 4.12 section 4.13

Operator precedence is a frequent source of mistakes. Addition has higher precedence than bitwise AND, and comparisons have higher precedence than bitwise AND, OR, and XOR. An expression intended to set a bit can therefore compute a different mask than it appears to compute. Avoid mixing arithmetic and bitwise operators; when bitwise operators are combined, use parentheses to make grouping explicit. section 2.1.2 section 2.2

Make a mask update explicit

The expression `bits & 0xFF00 + 1` is evaluated as `bits & 0xFF01`, so its low bit is copied rather than unconditionally set. Use OR to set the bit, and parentheses to show the intended grouping: `return (bits & 0xFF00) | 1;` section 2.1.2

Shifts have boundary and type traps. For `int`, Java reduces a shift distance modulo 32; thus `1 << 32` is the same as `1 << 0`. A mask intended to preserve 32 bits may instead clear every bit. Also, a left shift’s result type follows its left operand: use `1L << k` when setting a bit in a `long` field. section 4.12

Signed values matter when bytes or hexadecimal literals are widened. A negative `byte` widened to `int` fills its higher bits with ones, corrupting a value assembled with shifts and OR. Mask each byte with `0xFF` before combining it. Likewise, a hexadecimal `int` literal may represent a negative value; add an uppercase `L` suffix for a `long` mask. section 4.13 section 4.8

Compose unsigned byte contents

Combining signed bytes directly can return `-1` when the low byte is `-1`: `return (hi << 8) | lo;` Clear the widened sign bits before shifting and combining: `return ((hi & 0xFF) << 8) | (lo & 0xFF);` section 4.13

Reduce bit-operation mistakes with a few rules:

  • Keep arithmetic and bitwise work in separate expressions; parenthesize uncommon operator combinations. section 2.1.2
  • Encapsulate low-level masks and shifts in tested utility methods rather than repeating them inline. section 4.13 section 4.5
  • Treat static-analysis findings as useful prompts, not complete protection: precedence and raw-byte inspections can be disabled or cover only particular patterns. section 2.1.2 section 4.13
  • Use unsigned right shift for the nonnegative binary-search midpoint overflow case, but do not apply that trick when inputs can be negative. section 4.2.1
return ((hi & 0xFF) << 8) | (lo & 0xFF);

Compare the unsafe byte-composition expression with the corrected form that masks both widened bytes before shifting and OR-ing them. section 4.13

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Works through precedence, shift-distance rules, result types, sign extension, literal widening, and concrete corrected expressions.
Examples
Uses a flag-mask update, least-significant-bit mask, long bit setter, two-byte reader, binary-search midpoint, and oddness check.
What you can do after
Apply bit masks, shifts, and explicit grouping while avoiding signed-byte, long-literal, and boundary-shift errors.
How it connects
Connects operator precedence, bit masks, shift operations, integer overflow, sign extension, type widening, and static analysis.

Also explained in

Compare how 6 books explain bit operation →

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.