Back to Blog
Java

java && vs &: Short-Circuit vs Bitwise AND

java && vs &: Understand the difference between Java's && and & operators: short-circuit evaluation, bitwise operations, and when to use each.

java operatorsbitwise operationsshort-circuit evaluationboolean logicbit masking
Diagram contrasting Java's && short-circuit logical AND with & bitwise AND on integer bits.

The distinction between java && vs & is a frequent source of confusion in code reviews and debugging sessions. The && operator is a short-circuit logical AND that works only on boolean expressions. The & operator is a bitwise AND for integer types and can also serve as a non-short-circuit logical AND when applied to booleans. Choosing the wrong one can produce incorrect results, trigger unnecessary evaluation, or cause exceptions that a short-circuit would have avoided.

The Short-Circuit Behavior of &&

The && operator evaluates its left operand first. If the left operand is false, the right operand is never evaluated, and the expression returns false immediately. This is called short-circuit evaluation.

String input = getInput(); boolean result = (input != null) && (input.length() > 10);

When input is null, the first condition evaluates to false, and the second condition is skipped entirely. The expression avoids a NullPointerException because input.length() is never invoked.

Short-circuiting is not just a convenience; it is a guarantee of the Java language specification. The right operand is evaluated only if the left operand is true. This behavior is the primary reason && is the default choice for chaining boolean conditions in if statements and loop guards.

How & Handles Boolean Operands

When & is applied to two boolean operands, it behaves as a logical AND but without short-circuiting. Both operands are always evaluated.

String input = getInput(); boolean result = (input != null) & (input.length() > 10);

If input is null, the first operand is false, but the second operand is still evaluated, and input.length() throws a NullPointerException. The result of the expression is never reached because the exception interrupts execution.

This non-short-circuit behavior is occasionally useful when both sides of the expression have side effects that must run regardless of the first result. However, relying on it for side effects makes the code harder to read and is generally discouraged. If you need both sides to execute, an explicit sequence of statements is clearer than a single & expression.

Bitwise AND on Integer Types

On integer types such as int, long, short, byte, and char, & performs a bitwise AND. Each bit of the left operand is combined with the corresponding bit of the right operand. A result bit is 1 only when both input bits are 1.

int flags = 0b1100; int mask = 0b1010; int result = flags & mask; // 0b1000

The binary representation makes the operation visible: 1100 & 1010 yields 1000. The second bit from the left is 1 in both operands, so it survives in the result. All other bits are cleared.

Bitwise AND has no short-circuit concept because both operands are values, not conditions. The operation always examines every bit position in both operands.

Bit Masking and Flag Checks

Bitwise AND is the standard tool for extracting or testing individual bits within an integer. A common pattern is representing a set of permissions or options as individual bits in a single int.

public static final int READ = 1; public static final int WRITE = 2; public static final int EXECUTE = 4; int permissions = READ | WRITE; if ((permissions & READ) != 0) { // READ permission is present }

The expression permissions & READ produces 1 when the READ bit is set and 0 when it is not. Comparing the result to zero tells you whether the bit is present. The same technique applies to any flag set that fits within the bit width of the chosen integer type.

Bit masking is also used to clear bits. The expression permissions & ~WRITE removes the WRITE bit while leaving the others unchanged. This works because ~WRITE has 0 in the WRITE position and 1 everywhere else.

When Both Sides Must Be Evaluated

There are rare cases where both operands of a logical AND must be evaluated even when the first is false. For example, two operations may each need to run and their combined success determined.

boolean success = updateCache() & persistToDatabase();

Both updateCache() and persistToDatabase() execute regardless of the first result. With &&, a false from updateCache() would skip the persistence call entirely, which may or may not be the intended behavior.

Using & this way is legal but often unclear. A developer reading the code may not immediately recognize that both methods are guaranteed to run. Writing the two calls as separate statements and combining the results afterwards makes the intent explicit:

boolean cacheUpdated = updateCache(); boolean persisted = persistToDatabase(); boolean success = cacheUpdated && persisted;

This version is longer but communicates the evaluation order unambiguously.

Performance and Runtime Considerations

The short-circuit behavior of && can reduce work when the left operand is frequently false. If the right operand involves an expensive method call or a database query, skipping it entirely avoids that cost. The JVM does not reorder or eliminate these evaluations because the language specification requires the observable behavior to match the source code.

& on integers is a single CPU instruction on virtually every modern architecture, so its runtime cost is negligible. The cost concern with & on booleans is not the operation itself but the fact that both operands are always evaluated. If the right operand is expensive or has side effects, & forces that work to happen even when the left operand is false.

There is no meaningful performance difference between && and & when both operands are simple variable comparisons. The difference appears only when evaluation of the right operand has a cost worth avoiding.

Common Mistakes with && and &

The most frequent mistake is using & where && was intended. This typically appears in null checks or validation chains:

// Risky: throws if input is null if ((input != null) & (input.length() > 0)) {

The & operator evaluates input.length() even when input is null, producing a NullPointerException. The same condition with && is safe.

The reverse mistake, using && where bitwise AND is required, produces a compile error because && accepts only boolean operands. The compiler rejects the code rather than silently producing wrong results, which is the better failure mode.

Another common issue is using & for boolean logic when the intent is short-circuiting, then debugging why an exception occurs or why a method runs more often than expected. The fix is usually to replace & with && and verify that the right operand is safe to skip.

Choosing the Right Operator

Use && for all boolean conditions where short-circuiting is desirable, which is almost every condition in normal control flow. The right operand is skipped when the left operand is false, and that is is the behavior most developers expect.

Use & on integer types when you need bitwise operations such as masking, flag testing, or bit clearing. There is no overlap with && here because && does not accept integer operands.

Use & on booleans only when both operands must be evaluated regardless of the first result. This is a narrow use case, and the code should make the reason explicit. In most situations, separating the two evaluations into distinct statements is clearer than relying on the non-short-circuit behavior of &.

The decision between && and & comes down to whether you are working with conditions or with bits. Conditions belong to &&, bits belong to &. When both sides of a boolean expression must run, & is available, but the code should justify why that evaluation order matters.

java && vs &: Short-Circuit vs Bitwise AND | RYUSLOG DEV