Operators
Arithmetic, logical, bitwise, comparison operators and short-circuit evaluation
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, buts = 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â alwaysfalse- 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 |
2.9 Evaluation Order vs. Precedence
These two concepts are often confused.
- Precedence decides how an expression is grouped
- Evaluation order decides when operands are evaluated
Java guarantees left-to-right operand evaluation, but that does not remove the need for parentheses. A readable expression is usually better than a clever one.
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 |
Practical Rules of Thumb
- Prefer clarity over brevity in conditionals
- Use parentheses even when precedence would technically be correct
- Avoid side effects inside expressions that are also doing branching
- Use bitwise operators only when the domain is genuinely bit-oriented
- Prefer
Objects.equals(a, b)when null-safety matters
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. Deep Dive
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 isdouble - Otherwise, if either is
floatâ result isfloat - Otherwise, if either is
longâ result islong - Otherwise: both are promoted to
int(even ifbyte+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";
};
7.6 Bit Masks Still Matter in Real Systems
Even though many applications can use enums and booleans, bit masks still appear in permission systems, protocol parsers, binary file formats, and low-level frameworks.
The important rule is not ânever use bitwise operatorsâ, but âuse them where the data model is truly bit-based and document the intent clearlyâ.
7.7 Side Effects in Expressions Hurt Maintainability
This is legal Java:
if (cache != null && cache.refreshIfExpired()) {
// ...
}
But mixing state mutation and condition checking makes debugging harder. In business code, splitting the logic into separate steps is often the better trade-off.
8. Interview Questions
What is the difference between precedence and evaluation order?
Precedence determines how the compiler groups operators, while evaluation order determines when operands are executed. In Java, operands are evaluated left-to-right, but precedence still decides the structure of the expression.
Why is `&&` usually preferred over `&` in conditions?
Because && short-circuits. If the left side is already false, Java skips the right side, which both improves readability and prevents accidental NullPointerException in guard conditions.
Why does `byte + byte` become `int`?
Because Java applies numeric promotion rules during arithmetic. Operands smaller than int are promoted to int before the operation, so the result must be stored in int unless you cast explicitly.
When is the ternary operator a good choice?
It is a good choice when both branches are short, side-effect free, and clearly express a value. Once nesting starts or the branches do meaningful work, if-else or switch is usually better.
9. 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., +, &&) |
10. Cheatsheet
- Integer division:
7 / 2 = 3â use7.0 / 2or 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 += 1compiles,s = s + 1doesn't (ifsis short/byte) - Numeric promotion:
byte + byte = intâ explicit cast needed to assign back - NaN:
Double.NaN != Double.NaNâ useDouble.isNaN() - instanceof null:
null instanceof Anythingâ alwaysfalse - 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
10 questions