Back to Blog
Java

Java || vs |: Logical and Bitwise OR Explained

java || vs |: Understand the difference between || and | in Java, including short-circuit behavior, bitwise semantics, and when to use each.

Java operatorsshort-circuit evaluationbitwise operationsconditional logicboolean expressions
A split diagram showing Java's logical OR with short-circuit alongside bitwise OR, illustrating the difference between boolean and integer contexts.

Java's || and | operators look similar, but a single character can change program behavior. The difference is not just stylistic: || is a conditional-or operator, while | is a bitwise-or operator. In boolean contexts, | can be used as a non-short-circuit logical OR, but it behaves differently in numeric contexts. Understanding this distinction matters because it affects control flow, performance, and correctness.

The Basic Difference: Short-Circuit vs Full Evaluation

The most important difference between || and | is short-circuiting. When you use ||, Java evaluates the left-hand operand first. If it evaluates to true, the right-hand operand is never evaluated, because the overall expression is already known to be true. This is called short-circuit evaluation.

With |, both operands are always evaluated, regardless of the value of the left operand. The expression a | b evaluates both a and b, then applies the operation appropriate to the operand types: bitwise OR for integral types, and logical OR for boolean types, but without short-circuiting.

Consider this example:

boolean first() { System.out.println("first"); return true; } boolean second() { System.out.println("second"); return false; } boolean result1 = first() || second(); // prints "first", result1 is true boolean result2 = first() | second(); // prints "first" and "second", result2 is true

In the first line, second() is not called because first() already returned true. In the second line, second() is called even though the result is unnecessary. This can have side effects, performance implications, or even cause exceptions if the second operand has unwanted effects.

Bitwise OR on Integers

When applied to integer types (int, long, short, char, byte), | performs a bitwise OR. It combines the bits of the two values. For example:

int flags = 0b1010; int mask = 0b1100; int result = flags | mask; // result is 0b1110

Here, | sets a bit in the result if the bit is set in either operand. This is a common pattern for combining flag values, as seen in java.awt.event.InputEvent masks.

The || operator does not work on integers. It only accepts boolean expressions. Attempting to use || with integer operands results in a compile-time error.

Boolean Context: | as Non-Short-Circuit Logical OR

In a boolean expression, | behaves like a logical OR but without short-circuiting. This can be useful when you need both sides to be evaluated, for example, to ensure that some side effect occurs on both sides.

if (checkLeft() | checkRight()) { // do something }

This evaluates checkRight() even if checkLeft() returned true. In contrast, || would skip checkRight() in that case.

However, this is rarely recommended. In most situations, short-circuiting is desirable because it can avoid unnecessary work and prevent errors. A common pattern is to use || for control flow and to use & or | with booleans only when you explicitly need to evaluate both operands.

Practical Use Cases: When | Is Justified

There are a few legitimate use cases for the non-short-circuit | with booleans.

Side Effects Required on Both Sides

If you have two independent operations that both mutate state and you need to know whether at least one succeeded, you might want to evaluate both:

boolean changed = updateCache() | notifySubscribers();

If updateCache() returns true but notifySubscribers() must still be called, || would skip the second call. However, such code is often harder to read and maintain. A clearer approach may be to evaluate both explicitly:

boolean cacheUpdated = updateCache(); boolean notified = notifySubscribers(); boolean changed = cacheUpdated | notified;

This makes the intent explicit and avoids the implicit non-short-circuit behavior.

Bitmask Operations

For bitmask operations, | is the correct operator. For example, when opening a file with multiple options:

Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND);

This API takes multiple OpenOption arguments. When a method takes an int bitmask instead, | is the operation that combines individual flag constants.

Operator Precedence and Associativity

Both || and | are binary operators. | has higher precedence than ||. This means that in an expression without parentheses, | is grouped more tightly than ||. Chaining multiple | operators is left-associative, so a | b | c means (a | b) | c.

Consider this expression:

boolean result = a || b | c;

Because | has higher precedence, it is evaluated as a || (b | c). If a is true, the entire expression is true, and b | c is not evaluated due to short-circuiting. If a is false, then b | c is evaluated, and the result is the boolean OR of b and c (with both evaluated). This can lead to subtle bugs if you assumed left-to-right evaluation without precedence.

When mixing && and ||, the precedence order is: && higher than ||. This is a common source of confusion. Always use parentheses when mixing logical operators if the intended grouping is not obvious.

Type Compatibility: When Each Operator Compiles

|| requires both operands to be boolean (or Boolean with unboxing). | works with boolean types and also with integral types. Using | with booleans is valid, but using || with integers is not.

| Operand type | || | | | | --- | --- | --- | | boolean | Yes, short-circuit | Yes, no short-circuit | | int, long | No | Yes, bitwise | | short, char, byte | No | Yes, bitwise (after promotion) |

For a Boolean operand, either operator unboxes it to primitive boolean when that operand is actually evaluated. If a Boolean is null and is evaluated, unboxing throws a NullPointerException with either operator; || can avoid the problem by short-circuiting before the right operand is evaluated.

Performance Considerations

Performance differences between || and | are negligible in ordinary code. The JVM can optimize boolean expressions, and short-circuiting often saves work that would otherwise be wasted. The main performance concern is avoiding unnecessary calls to methods that are expensive or that have side effects.

If your right-hand operand is a costly computation, || can save time by skipping it when not needed. For example:

if (isCached() || loadFromDisk()) { // use the data }

If isCached() returns true, the expensive loadFromDisk() is not invoked. Using | here would always load from disk, which could be a significant performance hit in a hot path.

Common Mistakes and Pitfalls

A frequent mistake is using | when || is intended, especially when the operands are method calls. This can lead to unexpected side effects or performance problems. Another common mistake is using || with integer values, which causes a compile error.

Some developers use | in boolean expressions to guarantee both sides execute, but this often indicates unclear intent. It is better to refactor such code to make the evaluation order explicit.

Another pitfall is forgetting operator precedence when mixing &, |, &&, and ||. For example:

boolean b = x == 1 | y == 2;

This is valid because == has higher precedence than |. However, x == 1 || y == 2 is equivalent in result but short-circuits if x is 1. The difference matters if y is a method call or an expression with side effects.

When | Is Required for Bitwise Logic

The clearest place where | is indispensable is bitwise operations on integers. For example, combining permission flags:

int read = 1 << 0; int write = 1 << 1; int execute = 1 << 2; int allowed = read | write;

To check if a particular permission is set, you would use &:

if ((allowed & read) != 0) { // can read }

This pattern appears in legacy code, network protocols, and certain configuration APIs. If you are working with such APIs, | is the correct tool. For boolean logic, stick with || unless you have a specific reason to force both evaluations.

Understanding the NullPointerException Risk

When using reference Boolean values, either operator unboxes an operand at the point that operand is evaluated. If a Boolean is null, that unboxing throws NullPointerException. This is not special to these operators; any unboxing operation does the same. But || can avoid evaluating the right operand, and therefore avoid the unboxing:

Boolean a = null; Boolean b = true; boolean result = b || a; // no exception, a is not unboxed boolean result2 = b | a; // NullPointerException, a is unboxed

In the first line, b is true, so a is never unboxed. In the second line, a is unboxed, triggering an exception. This is a concrete example of how | forces full evaluation and why it can cause failures that || would avoid.

Final Section: Choosing Between || and | in Maintainable Code

In production code, the default choice should be || for boolean conditions. It is the standard operator, it short-circuits, and it is immediately understood by other developers. If you need bitwise combination of integer flags, use |. Using | with booleans is rare and should be accompanied by a comment explaining why both operands must be evaluated.

When reviewing code that uses | with booleans, check whether short-circuiting would change behavior. If both sides must always execute, consider extracting them into separate statements or methods to make the requirement obvious. This improves readability and reduces the chance of someone later "optimizing" the code by replacing | with ||, which might break the intended side effects.

Ultimately, the choice between || and | is governed by semantics: || is for boolean logic with short-circuiting, | is for bitwise operations or explicit full evaluation of boolean operands. Keeping that distinction clear in your code helps avoid subtle bugs and keeps the intent readable.

java || vs |: Practical Usage and Code Examples | RYUSLOG DEV