Topic 30 of 119 3. Operators in Java Interactive Tutorial

Java Operator Precedence and Associativity: Complete Evaluation Order

10 mins read Last updated: 22 Aug 2026 20,190 views

Direct Answer & Core Concept

Java groups operators into fifteen precedence levels, from postfix operators at the top to the lambda arrow at the bottom. Higher precedence binds tighter, so `2 + 3 * 4` groups as `2 + (3 * 4)`. When two operators sit at the same level, associativity decides: almost every binary operator in Java is **left-associative**, grouping left to right so `100 / 10 / 5` is `(100 / 10) / 5` and equals `2`, while `2 - 3 - 4` is `-5`. The exceptions are the unary prefix operators, the ternary conditional, and assignment, which are **right-associative**, which is what makes `a = b = c = 10` legal and gives `score >= 90 ? "A" : score >= 80 ? "B" : "C"` its natural ladder reading. Parentheses override everything, and are the only reliable way to express intent. The one level that surprises newcomers is that `+` is both arithmetic and string concatenation: because concatenation is left-associative, `1 + 2 + "3"` produces `33` while `"3" + 1 + 2` produces `312`. Note also that relational operators sit above equality, so `<` binds tighter than `==`, and that the bitwise operators `&`, `^` and `|` sit *below* equality, which surprises people coming from C. There is no chained comparison in Java, since `1 < 2 < 3` does not compile.

Detailed Explanation & Mechanics

1. Two Rules, Not One

Precedence problems are easier to reason about once you split them into two separate ideas. **Precedence** decides which operator grabs an operand first, so it only matters when two different operators compete. **Associativity** decides the grouping when two operators of *equal* precedence compete, and it applies only within a single level.

Main.java
Run Online
precedence which operator binds tighter 2 + 3 * 4 -> 2 +(3 * 4), because * is higher associativity which of two equal operators goes first 100 / 10 / 5 ->(100 / 10) / 5, because / is left-associative

The practical consequence is that precedence questions are about the table below, while associativity questions only ever arise inside a single row of it.

Main.java
Run Online
int a = 10 + 5 * 2;
// precedence: * first, so 20
int b =(10 + 5) * 2;
// parentheses: 30
int c = 100 / 10 / 5;
// associativity: left to right, so 2

2. The Complete Precedence Table

This is the whole table, from highest to lowest. Numbering from the top is the usual convention, and reading it bottom-up is how the compiler reads it.

LevelOperatorsAssociativityPurpose
1postfixexpr++ expr--LeftArray and field access, method calls, increment
2unary++ -- + - ~ !RightPrefix increment, negation, complement
3cast(type)RightType conversion
4multiplicative* / %LeftMultiply, divide, remainder
5additive+ -LeftAdd, subtract, and string concatenation
6shift<< >> >>>LeftBit shifting
7relational< > <= >= instanceofLeftComparison and type testing
8equality== !=LeftEquality comparison
9bitwise AND&LeftBit mask, also non-short-circuiting and
10bitwise XOR^LeftBit toggle, also boolean exclusive or
11bitwise OR|LeftBit set, also non-short-circuiting or
12logical AND&&LeftShort-circuiting and
13logical OR||LeftShort-circuiting or
14ternary?:RightConditional expression
15assignment= += -= *= /= %= &= |= ^= <<= >>= >>>=RightStore a value
16lambda->RightLambda expression, lowest of all

Three entries deserve comment. instanceof sits at the relational level, not the type level, which is why it competes with < rather than with the cast operator. The cast operator binds *looser* than the prefix unary operators, so -x is (-x) and not -(x) in the way you might guess. And the lambda arrow is the lowest operator in the language, below assignment.

Main.java
Run Online
highest postfix ++ expr-- arr[i] obj.field method() unary ++ -- + - ~ ! cast(type) ... lowest lambda -> the table is read top to bottom for tightest to loosest binding

3. Why Relational Binds Tighter Than Equality

This ordering trips up developers arriving from C, where & binds tighter than the equality operators. In Java the bitwise operators are *below* equality.

Main.java
Run Online
System.out.println(true == true & false);
// false

Read it carefully and the result makes sense only one way. == is higher than &, so this groups as (true == true) & false, which is true & false, which is false. If & bound tighter the expression would be true == (true & false) and the answer would be false as well, which is why this example is a poor demonstration. The boolean XOR version separates them cleanly.

Main.java
Run Online
boolean p = true, q = false;
System.out.println((p | q) == true);
// true, with parens
System.out.println(p ^ q);
// true

The safe habit is to parenthesise whenever &, | or ^ appears in a condition, precisely because the precedence surprises people. These operators also do **not** short-circuit, so nullable != null && list.get(0).isEmpty() is the right form and nullable != null & list.get(0).isEmpty() throws.

Main.java
Run Online
// & does not short-circuit, so the right operand is always evaluated
String s = null;
System.out.println(s != null & s.isEmpty());
// throws NullPointerException

4. Shift Is Lower Than Arithmetic

Shift operators sit at level 6, below additive, which produces a genuinely surprising result for anyone assuming shifts bind tightly.

Main.java
Run Online
System.out.println(1 + 2 > 1 + 1);
// 2

The first line is (1 + 2) << 3, that is 3 << 3, which is 24. The second is 8 >> (1 + 1), that is 8 >> 2, which is 2. Both are low-precedence operations on a sum, which is the opposite of the intuition that a shift is a low-level arithmetic operation.

The classic consequence is the unsigned-shift gotcha on a negative value.

Main.java
Run Online
System.out.println(-1 >>> 0);
// -1, not a large positive number
System.out.println(-1 >> 0);
// -1, the sign is preserved
System.out.println((-1 >>> 0) + 1);
// 0

-1 >>> 0 looks like it should produce a large unsigned value, but the result is still -1, and widening does not change that.

Main.java
Run Online
System.out.println(-1 >>> 0);
// -1
System.out.println(-1L >>> 0);
// -1, still, and the cast is not the issue
System.out.println(Long.toHexString(-1L >>> 0));
// ffffffffffffffff

The reason is that a shift count of 0 is an **identity**: shifting by zero positions returns the value unchanged, unsigned or not. The hex output shows all sixteen bits still set, which is what -1 is in two's complement.

Main.java
Run Online
System.out.println(-1L >>> 1);
// 9223372036854775807, now the top bit really does go
System.out.println(-1L >>> 32);
// 4294967295
System.out.println(-1L >>> 60);
// 15

So if you want to reinterpret a signed value as unsigned, a shift by zero is never the tool. Use a nonzero shift, or ask for the unsigned text directly.

Main.java
Run Online
System.out.println(Long.toUnsignedString(-1L));
// 18446744073709551615
System.out.println(Integer.toUnsignedLong(-1));
// 4294967295

5. Additive Is Also String Concatenation

Level 5 is not just addition. The + operator becomes string concatenation as soon as either operand is a String, and because the level is left-associative the operand that comes first decides what happens.

Main.java
Run Online
System.out.println(1 + 2 + "3");
// "33"
System.out.println("3" + 1 + 2);
// "312"

These two are the classic demonstration. In the first, the leftmost operation is 1 + 2, giving the number 3, which then concatenates with "3" to give "33". In the second, the leftmost operation is "3" + 1, giving the string "31", which then concatenates with 2 to give "312". Addition and concatenation are the same operator, so the grouping decides which one you get.

Main.java
Run Online
System.out.println(1 + 2 + 3 + "4");
// "64", the numbers add first
System.out.println("n = " + 1 + 2);
// "n = 12", both then concatenate

The fix is an explicit parenthesis or a local variable when mixing the two.

Main.java
Run Online
System.out.println(1 +(2 + "3"));
// "123", so parens alone do not add the numbers
int sum = 1 + 2;
System.out.println(sum + "3");
// "33", with the arithmetic named

Parentheses control the grouping but cannot change the fact that the outer + still concatenates. The only way to get arithmetic is to perform it where both operands are numbers, which means extracting the sum into a variable or writing a separate statement.

This also explains the confusing ternary output from the previous topic. "value: " + 5 + (true ? 1 : 2) produces text beginning 51, because the + chain consumes everything to its right before the ternary is ever consulted.

6. Associativity: Almost Everything Is Left

Every binary arithmetic, relational, equality, bitwise and logical operator is left-associative. The rule is simple to state and its consequences are not always obvious.

Main.java
Run Online
System.out.println(2 - 3 - 4);
// -5, that is (2 - 3) - 4
System.out.println(100 / 10 / 5);
//  2, that is (100 / 10) / 5
System.out.println(2 * 3 % 4);
//  2, that is (2 * 3) % 4

Subtraction and division are not associative, so the grouping changes the answer. This is the single most useful thing to internalise, because writing a / b / c when you meant a / (b / c) is a bug that compiles cleanly.

Main.java
Run Online
2 - 3 - 4 left assoc(2 - 3) - 4 = -5 2 -(3 - 4) 2 -(-1) = 3 a different answer 100 / 10 / 5 left assoc(100 / 10) / 5 = 2 100 /(10 / 5) 100 / 2 = 50 a different answer

Shifts are left-associative too, which surprises people because shifts are often assumed to be right-associative by analogy with exponentiation.

7. The Right-Associative Operators

Three groups are right-associative: the prefix unary operators, the ternary, and assignment. Each has a purpose the left-associative form could not serve.

Assignment is right-associative so that chained assignment works, and this is what makes declaring several variables of the same type on one line legal.

Main.java
Run Online
int x, y, z;
x = y = z = 100;
System.out.println(x + " " + y + " " + z);
// 100 100 100

The rightmost assignment happens first, so z is set, then y is set to the result, then x. Each variable receives the same value because the assignment expression evaluates to the value assigned.

The ternary is right-associative, which gives the threshold ladder its natural reading direction.

Main.java
Run Online
int score = 85;
String grade = score >= 90 ? "A" : score >= 80 ? "B" : "C";
// "B"

That groups as score >= 90 ? "A" : (score >= 80 ? "B" : "C"), so the best grade is checked first. The reverse nesting is legal and unreadable.

The prefix unary operators are right-associative, which is why a stack of ! or ~ unwinds from the right.

Main.java
Run Online
System.out.println(!!true);
// true
System.out.println(~~5);
// 5, applying it twice is the identity

Note that the compound assignment operators share this level, so a += b += c also evaluates right to left, with b updated first.

8. Parentheses and Casts

Parentheses sit above every operator, so they override precedence completely. This is the only mechanism for expressing a grouping the table would not choose.

Main.java
Run Online
int a = 10 + 5 * 2;
// 20
int b =(10 + 5) * 2;
// 30
int c = 10 +(5 * 2);
// 20, redundant but harmless

The cast operator binds looser than the prefix unary operators, so -x applies the negation to the cast value rather than the other way round. This matters for integer division and narrowing.

Main.java
Run Online
int i = -7;
System.out.println(-i / 2);
// 3, that is (-7) / 2
System.out.println(i / -2);
// 3, by the same rule
System.out.println(-i % 2);
// 1, because the negation applies first

A parenthesised expression cannot be the target of an increment, because increment needs a *variable*, and parentheses turn a variable into a value.

Main.java
Run Online
int j = 5;
int r =(-j)++;
// error: unexpected type

The same rule is why the final keyword blocks increment. Reading a final field yields a value rather than a variable, and the increment operators need a variable.

Main.java
Run Online
final int k = 5;
// k++;    error, a final variable cannot be incremented

9. Postfix Versus Prefix Increment

Postfix sits at the top of the table and prefix one level below, so in a combined expression the two increment forms behave differently. The difference is not precedence but *when* the increment is applied relative to the value produced.

Main.java
Run Online
int x = 5;
System.out.println(x++ + ++x);
// 12, and x ends at 7

Postfix yields the old value and increments afterwards, while prefix increments first and then yields the new value. In that expression the x++ yields 5 and leaves x at 6, then ++x raises it to 7 and yields 7, giving 12.

Postfix binds tighter than unary, which is visible in an index expression.

Main.java
Run Online
int[] arr = {
    0, 1, 2
};
int i = 0;
int v = arr[i++];
// 0, arr[0] is read before i becomes 1
System.out.println(v + " " + i);
// 0 1
i = 0;
int w = arr[++i];
// 1, i becomes 1 before the read
System.out.println(w + " " + i);
// 1 1

Reading the same variable twice in one expression is legal, and deterministic, but hard to read. Use separate statements.

10. No Chained Comparisons

Java does not support 1 < 2 < 3. The first comparison produces a boolean, and a boolean cannot be compared with an int, so the expression is rejected.

Main.java
Run Online
System.out.println(1 < 2 < 3);
// error: bad operand types for binary operator '

This is a genuine improvement on languages that allow it, because even if it compiled it would be wrong. The grouping would be (1 < 2) < 3, and comparing a boolean with 3 is meaningless. Write the two comparisons explicitly.

Main.java
Run Online
int value = 5;
System.out.println(0 < value && value < 10);
// true

A related trap is the classic "unrolled" C idiom, which Java rejects for the same reason.

Main.java
Run Online
// invalid in Java
// if (low

11. Evaluation Order Is Not Just Precedence

Precedence and associativity decide the *structure* of an expression. They do not decide the order in which subexpressions run, and that is a separate rule in the language.

Operands of a single operator are evaluated left to right, and so are the arguments of a method call.

Main.java
Run Online
static int c = 0;
static int mark() {
    c++;
    return c;
}System.out.println(mark() + mark() + mark());
// 6, that is 1 + 2 + 3

The calls happen left to right even though + is associative, and the same rule applies to method arguments.

Main.java
Run Online
System.out.println(mark() + " " + mark());
// the first mark runs first

The left-hand operand of an assignment is evaluated before the right, which matters when it has side effects of its own.

Main.java
Run Online
int[] data = new int[3];
int idx = 0;
data[idx++] = idx;
// the element and the value are not independent
System.out.println(data[0] + " " + data[1] + " " + idx);
// 1 1 1

The assignment evaluates its left operand first, so data[0] is selected and idx becomes 1, and only then is the right side read as 1. That single write lands the value in slot 0, which is worth knowing before you write this shape on purpose.

The practical takeaway is that short-circuit operators change evaluation order deliberately. In a != null && a.isEmpty(), && guarantees the right operand is skipped when the left is false, and that guarantee is the entire reason to use it instead of &.

Main.java
Run Online
String s = null;
System.out.println(s != null && s.isEmpty());
// false, no exception
System.out.println(s != null & s.isEmpty());
// throws NullPointerException

12. Method Chaining

Chained calls look like they might be governed by precedence, but they are not. Each call returns a value, and the next call is applied to that value, so the order is determined by the types rather than by the table.

Main.java
Run Online
StringBuilder sb = new StringBuilder();
sb.append(1).append("x").append(2);
System.out.println(sb);
// 1x2
System.out.println(sb.length());
// 3

The chain works only because every intermediate call returns something the next can be called on. Break the chain and it stops compiling, which is a good property, since it means the type of each link is checked rather than discovered at run time.

Main.java
Run Online
String s = "abc";
System.out.println(s.length());
// fine, length() returns int
// System.out.println(s.length().length()); // error: int cannot be dereferenced

13. Cheat Sheet

QuestionAnswer
Highest precedencePostfix, then unary prefix
Lowest precedenceLambda ->, below assignment
Most binary operatorsLeft-associative
Right-associativePrefix unary, ternary, assignment
10 + 5 * 220
2 - 3 - 4-5, left-associative
100 / 10 / 52, left-associative
1 << 2 << 332, shift is left-associative
1 + 2 << 324, additive binds tighter than shift
8 >> 1 + 12, that is 8 >> 2
-1 >>> 0-1, a shift by zero is an identity
1 + 2 + "3""33"
"3" + 1 + 2"312"
< versus ==Relational binds tighter
== versus &Equality binds tighter, opposite of C
instanceof levelRelational, not type
Cast levelBelow prefix unary, above multiplicative
1 < 2 < 3Compile error, no chained comparison
Range testx >= lo && x <= hi
Parentheses levelAbove everything, overrides all grouping
x = y = z = 10Right-associative, all become 10
Ternary associativityRight, giving the threshold ladder
Method argumentsEvaluated left to right
x++ + ++x12, with x ending at 7
(-j)++Error, increment needs a variable
Increment a final variableError, it reads as a value not a variable

If you remember only one thing, make it the parentheses rule. Precedence is a table you can look up, associativity is a habit you can verify, but explicit parentheses cost nothing and remove the entire class of bug. Every expression involving subtraction, division, a shift, a bitwise operator, or a + next to a String is a candidate for parens, and the cases where you leave them out should be the ones where you have already confirmed the grouping.

Runnable Code Example: Java Operator Precedence and Associativity

Java 17+
Main.java
Run Online
public class PrecedenceDemo {
    public static void main(String[] args) {
        // multiplicative beats additive
        int result = 10 + 5 * 2;
        // 10 + 10 = 20
        int grouped =(10 + 5) * 2;
        // 15 * 2 = 30, parentheses win
        // binary operators are left-associative
        int chained = 100 / 10 / 5;
        // (100 / 10) / 5 = 10 / 5 = 2
        int leftMinus = 2 - 3 - 4;
        // (2 - 3) - 4 = -5
        // relational beats equality, and && beats ||
        boolean check = 5 + 3 > 6 && 2 * 4 < 10;
        // true
        // + is concatenation once a String appears, and it is left-associative
        String concat = 1 + 2 + "3";
        // "33"
        String other = "3" + 1 + 2;
        // "312"
        // shift binds looser than additive
        int shifted = 1 + 2 << 3;
        // (1 + 2) << 3 = 24
        // ternary is right-associative, so thresholds read as a ladder
        int score = 85;
        String grade = score >= 90 ? "A" : score >= 80 ? "B" : "C";
        // "B"
        System.out.println("result:   " + result);
        System.out.println("grouped:  " + grouped);
        System.out.println("chained:  " + chained);
        System.out.println("subtract: " + leftMinus);
        System.out.println("check:    " + check);
        System.out.println("concat:   " + concat);
        System.out.println("other:    " + other);
        System.out.println("shifted:  " + shifted);
        System.out.println("grade:    " + grade);
    }
}

Common Java Technical Interview Questions & Answers

Interview Prep
Q1

Which operator has the highest precedence in Java?

The postfix operators, which sit at level 1. That group covers array indexing, field access such as obj.field, method invocation, and the postfix increment and decrement. The prefix unary operators come next at level 2. Note that the cast operator is below both, so it does not sit at the top as it does in C, and the lowest operator in the language is the lambda arrow, below assignment.
Q2

What is the difference between precedence and associativity?

Precedence decides which of two operators at different levels binds tighter, so 10 + 5 * 2 is 20. Associativity decides the grouping of two operators at the same level, so 100 / 10 / 5 is 2 because division is left-associative. Nearly every binary operator in Java is left-associative, and the exceptions are the prefix unary operators, the ternary, and assignment, which are right-associative. Precedence questions are answered from the table, while associativity only ever arises within a single row of it.
Q3

Why does 100 / 10 / 5 equal 2 rather than 50?

Because the division operator is left-associative, so the grouping is (100 / 10) / 5, which is 10 / 5, giving 2. The intuitive reading of 100 / (10 / 5) would give 50, but that requires right-associativity, which Java does not have for arithmetic operators. Subtraction has the same property, so 2 - 3 - 4 is -5 rather than 3. This is a compile-clean bug rather than an error, so parenthesise whenever the order matters and the operator is not associative.
Q4

Which operators are right-associative in Java?

The prefix unary operators, the ternary conditional, and assignment, including the compound forms such as +=. Right associativity is what makes chained assignment work, since x = y = z = 10 assigns to z first, then y, then x, with every variable ending at 10. It is also what gives the ternary threshold ladder its natural reading, so score >= 90 ? "A" : score >= 80 ? "B" : "C" checks the best grade first. The compound assignment operators share the level, so a += b += c also evaluates the right side first.
Q5

Why does 1 + 2 + "3" produce "33" while "3" + 1 + 2 produces "312"?

Because + is both arithmetic addition and string concatenation, and the additive level is left-associative, so the leftmost operation decides what the rest becomes. In 1 + 2 + "3" the first operation is numeric addition giving 3, which then concatenates to give "33". In "3" + 1 + 2 the first operation is concatenation giving "31", which then concatenates to give "312". Parentheses control the grouping but cannot make the outer + become arithmetic, so the reliable fix is to compute the sum in a variable first.
Q6

Why is -1 >>> 0 still -1?

Because a shift count of zero is an identity: it returns the value unchanged regardless of the unsigned operator. You can confirm this with Long.toHexString, which shows all sixteen bits still set. This is a common misconception, since people expect the unsigned shift to reinterpret the bits as a large positive number. To actually see the unsigned interpretation you need a nonzero shift count, so -1L >>> 1 gives Long.MAX_VALUE, or you ask for the unsigned text with Long.toUnsignedString and Integer.toUnsignedLong.
Q7

Why is true == true & false false, and why does it surprise people?

In Java the bitwise operators &, ^ and | sit below the equality operators, which is the opposite of C, where & binds tighter. So the expression groups as (true == true) & false, which is true & false, giving false. The surprise is that many developers carry the C ordering over by habit. This example does not demonstrate the rule cleanly because both groupings give false, so use parentheses whenever a bitwise operator appears in a condition, and remember that & does not short-circuit, which makes it unsafe for a null guard where && is required.
Q8

Can you write 1 < 2 < 3 in Java?

No, it does not compile, giving bad operand types for binary operator '<'. The first comparison produces a boolean, and a boolean cannot be ordered against an integer, so the second comparison is rejected. This is an improvement over languages that permit the form, because even if it compiled it would be wrong: the grouping would be (1 < 2) < 3, comparing a boolean with the number 3. Write the range test as x >= low && x <= high instead.
Q9

What precedence does instanceof have, and where does the cast operator sit?

instanceof sits at the relational level, alongside <, >, <= and >=, rather than at some type level, which is why it competes with the comparison operators. The cast operator sits below the prefix unary operators and above the multiplicative operators. So -i / 2 negates i first and then divides, giving 3 for i of -7, and a cast binds more loosely than the unary minus that precedes it. One consequence worth knowing is that a parenthesised expression cannot be incremented, since parentheses turn a variable into a value, so (-j)++ is an error.
Q10

Does precedence determine the order subexpressions are evaluated?

No. Precedence and associativity determine the structure of the expression, while evaluation order is a separate rule: operands of an operator are evaluated left to right, and method arguments are evaluated left to right too, so mark() + mark() + mark() produces 1 + 2 + 3. The left-hand side of an assignment is also evaluated before the right. The main way code deliberately departs from the default order is short-circuit evaluation, where && and || skip the right operand entirely, which is exactly what makes them safe for null guards.
Q11

Why does x++ + ++x equal 12 rather than something else?

Because postfix and prefix increment differ in when they apply the change, not in precedence, though postfix does bind tighter. Starting from x of 5, x++ yields the old value 5 and leaves x at 6, then ++x raises x to 7 and yields 7, giving 12, and x ends at 7. The precedence difference shows in an index: arr[i++] reads the element first and then increments i, whereas arr[++i] increments i first and reads the new index, which is why the two lines return different values. Reading the same variable twice in one expression is legal and deterministic but hard to follow, so prefer separate statements.
Q12

What is the best practice for handling precedence in real code?

Parenthesise anything whose grouping is not obvious, especially subtraction, division, shifts, bitwise operators, and any + next to a String. The cost is zero and the benefit is that the next reader does not need to reconstruct the table, which is also how review comments get written. The precedence table itself is worth memorising for the middle rows, since multiplicative over additive, additive over shift, and shift over relational are the ones that catch people out. Do not rely on the default grouping for anything involving side effects, and remember that parentheses cannot change which overload or operator is chosen, only the grouping of the operands.

Key Takeaways, Best Practices & Clean Code Rules

Java Best Practice & Production Rules

Parenthesise anything whose grouping is not obvious to you, which in practice means every expression involving subtraction, division, a shift operator, a bitwise operator, or a + adjacent to a String. Parentheses cost nothing at run time and they remove the entire category of bug where a reviewer has to reconstruct the precedence table to check your intent. The cases you can safely leave bare are the ones you have already confirmed: 2 + 3 * 4 is always 20, and chained comparison operators of the same level are always left-associative, so 100 / 10 / 5 is always 2. Learn the middle of the table properly rather than memorising every row, since multiplicative over additive, additive over shift, and shift over relational are the orderings that actually surprise people. Two Java-specific orderings deserve permanent attention: the bitwise operators &, ^ and | sit below equality, the opposite of C, so always parenthesise a bitwise operator inside a condition; and the additive level doubles as string concatenation, which is why 1 + 2 + "3" is "33" and "3" + 1 + 2 is "312". When arithmetic is mixed with text, compute the arithmetic into a local variable rather than trying to fix it with parentheses, since parentheses can change the grouping but cannot turn an outer + from concatenation into addition. Prefer && and || over & and | for every condition involving a null check or a bounds check, because the bitwise forms do not short-circuit and will evaluate the right operand even when the left already answered the question. Do not rely on evaluation order for anything with side effects, and remember that reading the same variable twice in one expression, as in x++ + ++x, is deterministic but unreadable, so split it into separate statements. Write the parentheses for the person reading the code six months from now, which is also the person who will be reviewing your pull request today.
We value your privacy & transparency

OperateTools uses cookies and local storage to ensure basic tool functionality, preserve preferences, and analyze aggregated traffic. We never sell your personal data or index your document files. Learn more in our Privacy Policy.