Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a Java array index expression evaluated before checking if the array reference expression is null?

According to the JLS, runtime evaluation of an array access expression behaves as follows:

  1. First, the array reference expression is evaluated. If this evaluation completes abruptly, then the array access completes abruptly for the same reason and the index expression is not evaluated.
  2. Otherwise, the index expression is evaluated. If this evaluation completes abruptly, then the array access completes abruptly for the same reason.
  3. Otherwise, if the value of the array reference expression is null, then a NullPointerException is thrown.

So this code will print: java.lang.NullPointerException, index=2

class Test3 {     public static void main(String[] args) {         int index = 1;         try {             nada()[index = 2]++;         } catch (Exception e) {             System.out.println(e + ", index=" + index);         }     }      static int[] nada() {         return null;     } } 

The question is: for what reason do we need to first evaluate the index = 2 expression and not just throw the NullPointerException once the array reference is evaluated to null? Or in other words - why is the order 1,2,3 and not 1,3,2?

like image 722
Andrei Nepsha Avatar asked Mar 14 '19 11:03

Andrei Nepsha


2 Answers

An array access expression has two sub-expressions:

An array access expression contains two subexpressions, the array reference expression (before the left bracket) and the index expression (within the brackets).

The two sub-expressions are evaluated before the array access expression itself, in order to evaluate the expression.

After evaluating the two sub-expressions

nada()[index = 2]++; 

becomes

null[2]++; 

Only now the expression is evaluated and the NullPointerException is thrown.

This is consistent with the evaluation of most expressions in Java (the only counter examples I can think of are short circuiting operators such as && and ||).

For example, if you make the following method call:

firstMethod().secondMethod(i = 2); 

First you evaluate firstMethod() and i = 2, and only later you throw NullPointerException if firstMethod() evaluated to null.

like image 176
Eran Avatar answered Sep 20 '22 04:09

Eran


This is because in the generated bytecode there are no explicit null checks.

nada()[index = 2]++; 

is translated into the following byte code:

// evaluate the array reference expression   INVOKESTATIC Test3.nada ()[I // evaluate the index expression   ICONST_2   DUP   ISTORE 1 // access the array // if the array reference expression was null, the IALOAD operation will throw a null pointer exception   DUP2   IALOAD   ICONST_1   IADD   IASTORE 
like image 28
Thomas Kläger Avatar answered Sep 20 '22 04:09

Thomas Kläger