Demonstrate Unsigned Right Shift in Java
Problem
Unlike >>, the unsigned right shift operator (>>>) always fills the vacated leftmost bits with 0, ignoring the sign — for a negative number, that turns what should stay negative into a large positive value instead.
Given a negative integer, compare the result of a signed right shift against an unsigned right shift by the same amount.
Java Program
public class DemonstrateUnsignedRightShift {
public static void main(String[] args) {
int a = -8;
int signedResult = a >> 1;
int unsignedResult = a >>> 1;
System.out.println("a = " + a + " (" + Integer.toBinaryString(a) + ")");
System.out.println("a >> 1 = " + signedResult + " (sign bit copied in)");
System.out.println("a >>> 1 = " + unsignedResult + " (zero filled in)");
}
}Output
Core Logic
Running both >> and >>> on the same negative number side by side shows exactly where they diverge: only in what fills the vacated leftmost bit.
- 1
a's 32-bit form is11111111111111111111111111111000, sincea = -8is negative. - 2
a >> 1shifts right and fills the vacated leftmost bit with a copy of the sign bit — another1— keeping the result negative:-4. - 3
a >>> 1shifts right the same way, but always fills the vacated leftmost bit with a plain0, regardless of the original sign. - 4That single
0instead of1turns the result into a huge positive number,2147483644, instead of-4— the bits are mostly the same, but the sign bit's meaning has completely changed.
a = -8: >> gives -4 by preserving the sign, while >>> gives 2147483644 by treating the same bit pattern as an unsigned number.Key Point: For a positive operand, >> and >>> always agree, because there's no sign bit worth preserving differently — the divergence shown here only ever happens with negative numbers.
Key Concepts
Approach 2: Java 8
import java.util.function.IntBinaryOperator;
public class UnsignedRightShiftLambda {
public static void main(String[] args) {
int a = -8;
int shiftBy = 1;
// Each shift is stored as a named, reusable lambda
IntBinaryOperator signedShift = (x, y) -> x >> y;
IntBinaryOperator unsignedShift = (x, y) -> x >>> y;
System.out.println("a = " + a + " (" + Integer.toBinaryString(a) + ")");
System.out.println("a >> " + shiftBy + " = " + signedShift.applyAsInt(a, shiftBy) + " (sign bit copied in)");
System.out.println("a >>> " + shiftBy + " = " + unsignedShift.applyAsInt(a, shiftBy) + " (zero filled in)");
}
}
Output
Core Logic
Storing >> and >>> as two named IntBinaryOperators turns each contrasting shift into a reusable value instead of a one-off inline expression.
- 1
IntBinaryOperator signedShift = (x, y) -> x >> y;andIntBinaryOperator unsignedShift = (x, y) -> x >>> y;store each shift's logic as a separate lambda. - 2
signedShift.applyAsInt(a, shiftBy)andunsignedShift.applyAsInt(a, shiftBy)call them with the sameaandshiftBy, returning the same results the inline operators would. - 3The 32-bit binary string for
ais built exactly as before, and each result is printed with the same descriptive suffix as the direct version.
a = -8 and shiftBy = 1, signedShift.applyAsInt(-8, 1) returns -4 and unsignedShift.applyAsInt(-8, 1) returns 2147483644 — the same values the direct version prints.Key Point: Naming each lambda signedShift and unsignedShift makes the contrast between them explicit in the code itself — the same pattern used for the arithmetic and bitwise operator pages.