Java Operator Precedence: Rules and Common Mistakes
java operator precedence: Java operator precedence rules explained: associativity, common mistakes like string concatenation, and using parentheses for readable expres...
Java operator precedence determines the order in which operators are evaluated in an expression. When you write 2 + 3 * 4, the result is 14, not 20, because multiplication binds more tightly than addition. Expressions that violate precedence rules compile cleanly and run without errors, which makes them harder to trace than syntax errors. This article covers the precedence rules you need to read and write Java expressions correctly, along with the mistakes that most often trip up developers.
The Precedence Table
Java defines a fixed precedence for every operator. The table below lists operators from highest to lowest precedence. Operators in the same row have equal precedence.
| Rank | Operators | Category |
|---|---|---|
| 1 (highest) | ++ -- | Postfix |
| 2 | ++ -- + - ~ ! | Unary |
| 3 | * / % | Multiplicative |
| 4 | + - | Additive |
| 5 | << >> >>> | Shift |
| 6 | < > <= >= instanceof | Relational |
| 7 | == != | Equality |
| 8 | & | Bitwise AND |
| 9 | ^ | Bitwise XOR |
| 10 | | | Bitwise OR |
| 11 | && | Logical AND |
| 12 | || | Logical OR |
| 13 | ?: | Ternary |
| 14 (lowest) | = += -= *= /= %= &= ^= |= <<= >>= >>>= | Assignment |
The ordering matters in practice. Bitwise operators sit below equality operators, so a & b == c is evaluated as a & (b == c), not (a & b) == c. Logical AND sits above logical OR, so a || b && c is a || (b && c), which is usually what you want.
Associativity: What Happens When Precedence Is Equal
Precedence alone does not fully determine evaluation order. When two operators in an expression have equal precedence, associativity decides which one is evaluated first.
Most binary operators in Java are left-associative. The expression 10 - 4 - 3 evaluates as (10 - 4) - 3, producing 3. If it were right-associative, the result would be 10 - (4 - 3) = 9. Subtraction is not associative, so the difference matters.
Assignment operators and the ternary operator are right-associative. This is why chained assignment works:
int x, y; x = y = 5;
The expression y = 5 is evaluated first, then x = y. If assignment were left-associative, x = y would be evaluated first, which would not compile because y has no value yet.
Increment and Decrement Precedence
Postfix ++ and -- have the highest precedence of any operator in Java, above even the unary operators. This creates results that look wrong on first reading.
int x = 5; int y = -x++;
Because x++ binds tighter than the unary minus, the expression is -(x++). The postfix increment returns the original value 5 and then increments x to 6. The unary minus applies to the returned value, so y is -5. If you wanted to negate x before incrementing, you would write (-x)++, which does not compile because the result of unary minus is not a variable.
The same rule applies when increment or decrement appears inside a larger expression:
int[] values = {3, 7, 9}; int index = 0; int current = values[index++] * 2;
The postfix increment binds to index, so values[index++] reads values[0] and then advances index to 1. The multiplication then doubles the value 3, giving 6. The expression is equivalent to (values[index++]) * 2, not values[(index++) * 2].
String Concatenation and the Plus Operator
The + operator is overloaded in Java. It performs numeric addition when both operands are numeric, and string concatenation when either operand is a String. Precedence and associativity determine which behavior applies in mixed expressions.
System.out.println("Value: " + 2 + 3); System.out.println(2 + 3 + " Value");
The first line prints Value: 23. Because + is left-associative, "Value: " + 2 is evaluated first, producing the string "Value: 2". The next + then concatenates "Value: 2" with 3, producing "Value: 23".
The second line prints 5 Value. Both operands of the first + are integers, so 2 + 3 is numeric addition, producing 5. The second + then concatenates 5 with the string " Value".
This behavior is consistent with the precedence rules, but it is a common source of confusion because the same operator changes meaning based on operand types.
The Ternary Operator and Precedence
The ternary operator ?: has lower precedence than every binary operator except assignment. This means the branches are evaluated with the surrounding expression's operators binding more tightly.
boolean flag = false; int result = flag ? 1 : 2 + 3;
Because + binds more tightly than ?:, the expression is flag ? 1 : (2 + 3). When flag is false, the false branch evaluates 2 + 3, and result is 5. The ternary operator is also right-associative, which allows chained ternaries to nest from right to left:
int category = score >= 90 ? 1 : score >= 70 ? 2 : 3;
This evaluates as score >= 90 ? 1 : (score >= 70 ? 2 : 3). Chained ternaries are readable in simple cases, but nested branches beyond two levels are usually clearer as if/else statements.
Parentheses: The Practical Solution
Parentheses override precedence and make the intended evaluation order explicit. They are not only for changing behavior; they are the primary tool for making expressions readable.
int result = (2 + 3) * 4;
Every developer who reads this expression knows the addition happens first. The same expression without parentheses, 2 + 3 * 4, relies on the reader knowing that multiplication has higher precedence.
Parentheses also clarify expressions where precedence is technically correct but easy to misread:
boolean valid = (flags & MASK) != 0;
Without parentheses, flags & MASK != 0 would be evaluated as flags & (MASK != 0), which compares MASK to 0 first and then performs a bitwise AND with a boolean. The expression would not compile because & cannot take an int and a boolean. The parentheses make the intent obvious and prevent the error.
Readability and Maintainability
Knowing precedence rules is necessary for reading existing code, but writing new code that depends on obscure precedence relationships creates maintenance risk. A developer who misreads a & b == c as (a & b) == c will introduce a subtle bug when the actual evaluation is a & (b == c).
Use parentheses when an expression mixes operators from different precedence levels, even when the precedence is technically correct. The cost of two extra characters is lower than the cost of a misread expression. This matters most in code that other developers will modify, where the original author's intent must survive contact with future changes.
There is a balance. Writing a + b * c without parentheses is idiomatic and readable; most developers know that multiplication binds more tightly. Writing a & b == c without parentheses is not idiomatic, and the precedence relationship between bitwise AND and equality is not common knowledge. When in doubt, add parentheses.
Compound Assignment Operators
Compound assignment operators such as +=, -=, and *= have the same precedence as simple assignment, which is the lowest of all operators. The right-hand side is always fully evaluated before the compound operation applies.
int x = 10; x += 5 * 2;
Here, 5 * 2 is evaluated first because * has higher precedence than +=. The result, 10, is added to the current value of x, giving 20. If you expected (x + 5) * 2 = 30, the precedence rules say otherwise.
Compound assignment also includes an implicit cast to the variable's type. This is not a precedence rule, but it interacts with how you read compound assignments:
short s = 5; s += 1; // compiles, s is 6 s = s + 1; // does not compile: int cannot be converted to short
The compound form compiles because the assignment includes an implicit narrowing cast. The expanded form does not, because s + 1 produces an int and assigning an int to a short without a cast is a compile error. When you see a compound assignment, both the precedence of the right-hand side and the implicit cast affect the result.