Array assignment output behaves differently for two code snippets

First code snippet prints 2

public static void main(String args[]) throws Exception {  
    int[] a = { 1, 2, 3, 4 };
    int[] b = { 2, 3, 1, 0 };
    int val = (a = b)[3];
    System.out.println( a [val  ] );
}

Second code snippet outputs 1

public static void main(String args[]) throws Exception {
    int[] a = { 1, 2, 3, 4 };
    int[] b = { 2, 3, 1, 0 };
    int val;
    System.out.println(a[val = ((a = b)[3])]);
}

What is going on?

output1

2nd output

Jon Skeet
people
quotationmark

The output is reasonable. Let's expand the two complicated lines into several separate statements. First snippet:

// This...
int val = (a = b)[3];
// Becomes...
a = b;
int val = a[3]; // 0

So printing a[val] will print a[0], which is now 2.

The second snippet is more complicated. The tricksy bit is that "the array we're indexing into" is evaluated before the rest of the side-effects. So:

// This...
System.out.println(a[val = ((a = b)[3])]);
// Becomes...
int[] tmp = a; // So tmp is { 1, 2, 3, 4 }
a = b;
val = a[3]; // 0
System.out.println(tmp[val]); // 1

JLS section 15.10.4 goes into more detail about this. The important parts here are:

At run time, evaluation of an array access expression behaves as follows:

  • First, the array reference expression is evaluated. If this evaluation completes abruptly [...] evaluated.
  • Otherwise, the index expression is evaluated. If this evaluation completes abruptly [...]
  • Otherwise, if the value of the array reference expression is null [...]
  • Otherwise, the value of the array reference expression indeed refers to an array. If the value of the index expression is less than zero [...]
  • Otherwise, the result of the array access is the variable of type T, within the array, selected by the value of the index expression.

people

See more on this question at Stackoverflow