Beginner Reading time: ~11 min

Operators

Arithmetic, logical, bitwise, comparison operators and short-circuit evaluation

Operators and Expressions

Java operators and expressions: arithmetic, relational, logical, bitwise, assignment, ternary, instanceof operators, precedence, and evaluation order.

1. Definition

What is it?

An operator is a symbol that performs an operation on one or more operands and produces a result (value). An expression is a combination of operators and operands that evaluates to a single value.

Why does it matter?

  • Fundamental building block: every algorithm, condition, and loop relies on operators
  • Performance: choosing the right operator (e.g., bitwise shift vs. multiplication) can make a meaningful difference
  • Readability: understanding precedence and short-circuit evaluation is essential for bug-free code

Where does it fit?

Operators belong to the syntactic foundation layer of Java — directly above types and variables, and below control structures.


2. Core Concepts

2.1 Arithmetic Operators

Operator Description Example Result
+ Addition 5 + 3 8
- Subtraction 5 - 3 2
* Multiplication 5 * 3 15
/ Division 7 / 2 3 (integer division!)
% Modulo (remainder) 7 % 2 1
++ Increment i++ / ++i pre/post increment
-- Decrement i-- / --i pre/post decrement

⚠ Integer division: when both operands are integers, the result is an integer (the decimal part is truncated).

2.2 Relational / Comparison Operators

Operator Description Example
== Equal to a == b
!= Not equal to a != b
> Greater than a > b
< Less than a < b
>= Greater than or equal a >= b
<= Less than or equal a <= b

🔑 For primitives, == compares values. For objects, == compares references.

2.3 Logical Operators

Operator Description Short-circuit?
&& Logical AND ✅ Yes — if left is false, right is not evaluated
|| Logical OR ✅ Yes — if left is true, right is not evaluated
! Logical NOT —
& Logical AND (eager) ❌ No
| Logical OR (eager) ❌ No

2.4 Bitwise Operators

Operator Description Example
& Bitwise AND 0b1010 & 0b1100 → 0b1000
| Bitwise OR 0b1010 | 0b1100 → 0b1110
^ Bitwise XOR 0b1010 ^ 0b1100 → 0b0110
~ Bitwise NOT (complement) ~0b1010 → 0b...0101
<< Left shift 1 << 3 → 8
>> Signed right shift -8 >> 2 → -2
>>> Unsigned right shift -1 >>> 28 → 15

2.5 Assignment Operators

Operator Equivalent
= Simple assignment
+= a = a + b
-= a = a - b
*= a = a * b
/= a = a / b
%= a = a % b
&= a = a & b
|= a = a | b
^= a = a ^ b
<<= a = a << b
>>= a = a >> b
>>>= a = a >>> b

🔑 Compound assignment operators (e.g., +=) include an implicit cast: short s = 1; s += 1; ✅ compiles, but s = s + 1; ❌ compile error (int → short narrowing).

2.6 Ternary Operator (Conditional Expression)

result = (condition) ? valueIfTrue : valueIfFalse;

This is the only three-operand (ternary) operator in Java.

2.7 instanceof Operator

if (obj instanceof String s) {   // pattern matching (Java 16+)
    System.out.println(s.length());
}
  • null instanceof Anything → always false
  • Since Java 16, pattern matching allows declaring a variable inside instanceof

2.8 Operator Precedence Table

Priority Operator(s) Associativity
1 (highest) () [] . Left to right
2 ++ -- (postfix) Left to right
3 ++ -- (prefix) + - (unary) ~ ! Right to left
4 (type) cast Right to left
5 * / % Left to right
6 + - Left to right
7 << >> >>> Left to right
8 < <= > >= instanceof Left to right
9 == != Left to right
10 & Left to right
11 ^ Left to right
12 | Left to right
13 && Left to right
14 || Left to right
15 ? : Right to left
16 (lowest) = += -= etc. Right to left

3. Practical Usage

When to Use Which Operator?

Task Recommended Why?
Even/odd check n % 2 == 0 Simple, readable
Multiply/divide by power of 2 n << 1 / n >> 1 Performance (though JIT optimizes anyway)
Null-safe check obj != null && obj.method() Short-circuit guards against NullPointerException
Simple if-else value Ternary ? : More concise, but don't nest!
Flag management Bitwise &, |, ^ Memory-efficient, fast
Type checking instanceof + pattern matching Modern Java 16+ idiom

4. Code Examples

4.1 Basic Examples

// Integer division — common surprise
int a = 7 / 2;        // 3, NOT 3.5!
double b = 7.0 / 2;   // 3.5 — at least one operand is double

// Pre vs. post increment
int i = 5;
int x = i++;  // x = 5, i = 6 (post: assign first, then increment)
int y = ++i;  // y = 7, i = 7 (pre: increment first, then assign)

// Modulo with negative numbers
int mod = -7 % 3;  // -1 (result sign follows the dividend's sign)

4.2 Short-Circuit Evaluation

// ✅ Correct: short-circuit guards against NullPointerException
String name = null;
if (name != null && name.length() > 0) {
    System.out.println(name);
}

// ❌ Wrong: & is not short-circuit, will throw NullPointerException!
if (name != null & name.length() > 0) {  // đŸ’„ NPE!
    System.out.println(name);
}

4.3 Bitwise Flag Management

// Define flags
static final int READ    = 0b0001;  // 1
static final int WRITE   = 0b0010;  // 2
static final int EXECUTE = 0b0100;  // 4

// Set a flag
int permissions = READ | WRITE;          // 0b0011 = 3

// Check a flag
boolean canRead = (permissions & READ) != 0;   // true

// Clear a flag
permissions = permissions & ~WRITE;             // 0b0001 = 1

// Toggle a flag
permissions = permissions ^ EXECUTE;            // 0b0101 = 5

4.4 Ternary — Good and Bad Usage

// ✅ Simple and readable
String status = (age >= 18) ? "adult" : "minor";

// ❌ Nested ternary — unreadable!
String category = (age < 13) ? "child" : (age < 18) ? "teenager" : "adult";

// ✅ Use if-else or switch expression instead
String category;
if (age < 13) category = "child";
else if (age < 18) category = "teenager";
else category = "adult";

4.5 Compound Assignment Implicit Cast

short s = 10;
// s = s + 1;   // ❌ Compile error! (s + 1 = int, int → short narrowing)
s += 1;         // ✅ OK! += includes implicit cast: s = (short)(s + 1)

byte b = 127;
b += 1;         // ✅ Compiles, BUT overflow! b = -128

5. Trade-offs

Aspect Option A Option B When to choose?
Readability vs. brevity if-else Ternary ? : Ternary for simple one-liner choices; if-else for complex logic
Bitwise vs. conventional n * 2 n << 1 On modern JVMs there's no real speed difference; n * 2 is more readable
Short-circuit vs. eager && / || & / | Almost always short-circuit; eager only when both side effects are needed
== vs. equals() == .equals() == for primitives and reference identity; .equals() for content comparison

6. Common Mistakes

❌ 6.1 Integer Division Surprise

double result = 1 / 3;          // 0.0, not 0.333!
double correct = 1.0 / 3;       // 0.333...  ✅
double alsoCorrect = (double) 1 / 3;  // 0.333...  ✅

❌ 6.2 Precedence Pitfall

// Intent: (a & b) != 0
if (a & b != 0) { }   // ❌ Actually: a & (b != 0) — != has higher precedence than &!
if ((a & b) != 0) { }  // ✅ Use parentheses!

❌ 6.3 == vs. equals on Objects

String s1 = new String("hello");
String s2 = new String("hello");
s1 == s2;        // false — different references!
s1.equals(s2);   // true  ✅

❌ 6.4 Pre/Post Increment Side Effects

int i = 0;
int result = i++ + ++i;  // ❌ Confusing, looks platform-specific
// Well-defined in Java (result = 0 + 2 = 2), but AVOID this pattern!

❌ 6.5 Overflow in Compound Assignment

byte b = 127;
b += 1;     // -128! No compile-time warning, silent overflow

7. Senior-level Insights

7.1 Absence of Operator Overloading

Unlike C++ and Kotlin, Java does not support operator overloading. The only exception is the + operator for String concatenation, which the compiler rewrites to StringBuilder or invokedynamic (Java 9+).

7.2 Expression Evaluation Order (JLS §15.7)

The Java Language Specification guarantees that operands are evaluated left-to-right. This is not the same as precedence:

int i = 0;
int r = (i = 1) + (i = 2);  // r = 1 + 2 = 3, NOT 2 + 2!
// The left operand is evaluated before the right operand

7.3 Numeric Promotion Rules

  • If either operand is double → result is double
  • Otherwise, if either is float → result is float
  • Otherwise, if either is long → result is long
  • Otherwise: both are promoted to int (even if byte + byte!)
byte a = 10, b = 20;
// byte c = a + b;  // ❌ Compile error! a + b = int
int c = a + b;      // ✅

7.4 NaN and Infinity Behavior

double nan = Double.NaN;
nan == nan;           // false! NaN is never equal to itself
Double.isNaN(nan);    // true  ✅

double inf = 1.0 / 0; // Infinity, not ArithmeticException!
int zero = 1 / 0;     // đŸ’„ ArithmeticException (integer division)

7.5 Switch Expression vs. Ternary (Java 14+)

// Java 14+ switch expression — more readable than nested ternary
String type = switch (code) {
    case 1 -> "admin";
    case 2 -> "user";
    default -> "guest";
};

8. Glossary

Term Definition
Operator A symbol that performs an operation on operand(s)
Operand The value on which an operator acts
Expression A combination of operators and operands that evaluates to a single value
Precedence The priority order in which operators are evaluated
Associativity When precedence is equal, the direction of evaluation (left-to-right or right-to-left)
Short-circuit evaluation Skipping evaluation of the right operand when the result is already determined
Bitwise An operation applied to individual bits
Ternary operator A three-operand conditional expression (? :)
Numeric promotion Automatic conversion of smaller types to larger types during operations
Compound assignment Combined operation and assignment (+=, -=, etc.) with implicit cast
instanceof Type-checking operator, with pattern matching support since Java 16
Unary operator An operator with a single operand (e.g., !, ~, ++)
Binary operator An operator with two operands (e.g., +, &&)

9. Cheatsheet

  • Integer division: 7 / 2 = 3 — use 7.0 / 2 or explicit cast for decimals
  • Short-circuit: && and || → right side not evaluated if result is already determined
  • Precedence: when in doubt, use parentheses — (a & b) != 0
  • == vs. equals: == for primitives, .equals() for objects
  • Compound assignment: += includes implicit cast → s += 1 compiles, s = s + 1 doesn't (if s is short/byte)
  • Numeric promotion: byte + byte = int → explicit cast needed to assign back
  • NaN: Double.NaN != Double.NaN → use Double.isNaN()
  • instanceof null: null instanceof Anything → always false
  • Bitwise shift: 1 << n = 2ⁿ — useful for flags and powers of two
  • Ternary: one level deep max — if more complex, use if-else or switch expression
  • Evaluation order: JLS guarantees left-to-right evaluation, but don't rely on it with side effects!
  • Operator overloading: Java has none — except + for String concatenation

🎼 Games

8 questions