In a compound assignment to an array element or field, what is the evaluation order, and why can it matter?
answer
- LHS location evaluated once, first
- read old value → eval RHS → op → cast → store
- array: ref then index, then remembered
- i += i++ → defined, ends at 2
- left operand captured before RHS
basics
~20 sJava evaluates the target's location (like the array reference and index) first and only once, then reads the old value, applies the operation with the right-hand side, and stores back. So a method used to pick the slot runs a single time.
solid answer
~50 sFor `arr[idx()] op= expr`, the JLS fixes a specific order: first the array reference is evaluated, then the index expression `idx()`, and that location is remembered — evaluated exactly once. Then the current value at that slot is read, the right-hand side `expr` is evaluated, the binary operation is applied, the result is cast back to the element type, and finally stored to the same slot. The key consequence is that side effects in the target (index methods, the array reference itself) happen once, not twice as a naive `arr[idx()] = arr[idx()] + expr` rewrite would suggest. The left operand is also fully evaluated before the right operand, so if both have side effects, the left one happens first. This also explains why `i += i++` is well-defined in Java: the original `i` is read for the left operand before `i++` runs, so the post-increment's effect is overwritten by the final store.
code
java · 12 linesint[] a = {10, 20, 30};
int[] callCount = {0};
// index method that records how often it ran
java.util.function.IntSupplier idx = () -> { callCount[0]++; return 0; };
a[idx.getAsInt()] += 5; // idx runs ONCE
System.out.println(a[0]); // 15
System.out.println(callCount[0]); // 1
int i = 1;
i += i++; // left read=1, i++ -> i=2 yields 1, sum=2, store overwrites
System.out.println(i); // 2go deeper
Knows the variable on the left gets updated; may not reason about evaluation order.
States that the LHS location is evaluated once and updates happen in place.
Lays out the full step order (LHS once → read → RHS → op → cast → store) and explains array-index single-evaluation and left-before-right capture.
Contrasts Java's specified sequencing with C/C++ undefined behavior, and sets team conventions banning side-effect-laden compound assignments despite being defined.
## Why order matters at all An **expression with side effects** changes state when evaluated — a method call, an increment (`i++`), an assignment. When such expressions appear inside a compound assignment, the *order* in which Java evaluates the pieces determines the result. Java's spec (JLS §15.26.2) pins this order down precisely; it is not implementation-defined. ## The exact steps for `E1 op= E2` 1. **Evaluate the LHS reference, once.** For a simple variable this is trivial. For `arr[idx()]`: - first evaluate the array reference (`arr`), - then evaluate the index (`idx()`), - and **remember that exact slot**. `idx()` runs **once**. For a field `obj.f`, `obj` is evaluated once. If evaluating the LHS throws (e.g. `arr` is null, index out of bounds), nothing further happens. 2. **Read the current value** at that remembered location, and save it as the left operand. 3. **Evaluate E2** (the right operand). (So the *left* operand value is captured *before* E2 is evaluated.) 4. **Apply the binary operator** to (saved left value, E2 value), with the usual numeric promotion. 5. **Cast the result** back to the type of E1 (the implicit narrowing cast). 6. **Store** the result into the remembered location. ## Consequence 1: target side effects happen once ``` int[] a = {10, 20, 30}; int i = 0; int next() { return i++; } // pretend this is a method a[next()] += 5; ``` With compound assignment, `next()` is called **once** (returns 0, i becomes 1); slot 0 is read (10), 5 added, 15 stored to slot 0. If you wrongly believed it expands to `a[next()] = a[next()] + 5`, you'd expect `next()` twice (slots 0 and 1) — a different, buggy result. ## Consequence 2: left-before-right ordering Because the left operand's value is captured in step 2 *before* E2 is evaluated in step 3, expressions like `i += i++` are deterministic: ``` int i = 1; i += i++; // left operand read = 1; then i++ makes i=2 and yields 1; sum=1+1=2; stored to i => i=2 ``` The final **store overwrites** the post-increment's write, so `i` ends at 2, not 3. (This is well-defined in Java — unlike C/C++, where such sequencing is undefined behavior.) Still, *don't write code like this*; it's a readability trap even if defined. ## Consequence 3: exceptions short-circuit cleanly If step 1 throws (null array, bad index), the read/op/store never happen — no partial state change at the target slot. ## Why simple `=` differs slightly Plain assignment `E1 = E2` evaluates the **target location of E1 first**, then **E2**, then stores. There's no read of the old value and no operator. Same left-to-right discipline, fewer steps. ## Practical guidance - Rely on "LHS evaluated once" — it makes `map.get(...)` style or indexed compound updates safe and concise. - Avoid stacking side effects inside one assignment (`a[f()] += g()` where both mutate shared state); even though defined, it's hard to read and review. - Remember Java's order is **specified and left-to-right**; never reason about it the way you would in C.
- How many times is the index evaluated in `a[k++] += 1;` and what is k afterward if it started at 0?The index `k++` is evaluated exactly once: it yields 0 (used as the slot) and increments k to 1. Slot 0 is read, incremented, and stored. So k ends at 1, not 2.
- Is `i += i++` undefined behavior in Java like in C?No. Java fully specifies left-to-right evaluation, so the left operand (original i) is read before i++ runs. The result is deterministic — for i=1 it ends at 2 because the final store overwrites the post-increment's write. It's still poor style, but it is well-defined.
saying these in an interview costs you the question
- Treating compound assignment as a textual macro that re-evaluates the LHS
- Believing Java evaluation order is unspecified like C/C++
- Expecting `i += i++` to be undefined or to end at 3
- Thinking the RHS is evaluated before the left operand value is captured