[Java] Booleani, operatori condizionali e autoboxing



Answers

La linea:

    Boolean b = true ? returnsNull() : false;

è internamente trasformato in:

    Boolean b = true ? returnsNull().getBoolean() : false; 

per eseguire l'unboxing; quindi: null.getBoolean() genererà un NPE

Questa è una delle maggiori insidie ​​quando si utilizza l'autoboxing. Questo comportamento è effettivamente documentato in 5.1.8 JLS

Edit: Credo che l'unboxing sia dovuto al fatto che il terzo operatore è di tipo booleano, come (cast implicito aggiunto):

   Boolean b = (Boolean) true ? true : false; 
Question

Perché questo lancia NullPointerException

public static void main(String[] args) throws Exception {
    Boolean b = true ? returnsNull() : false; // NPE on this line.
    System.out.println(b);
}

public static Boolean returnsNull() {
    return null;
}

mentre questo no

public static void main(String[] args) throws Exception {
    Boolean b = true ? null : false;
    System.out.println(b); // null
}

?

La soluzione consiste nel rimpiazzare false da Boolean.FALSE per evitare che null venga rimosso da un boolean - il che non è possibile. Ma questa non è la domanda. La domanda è: perché ? Ci sono riferimenti in JLS che confermano questo comportamento, specialmente del secondo caso?




Possiamo vedere questo problema dal codice byte. Alla riga 3 del codice byte principale, 3: invokevirtual #3 // Method java/lang/Boolean.booleanValue:()Z , il boxing Booleano del valore null, invokevirtual il metodo java.lang.Boolean.booleanValue , genererà NPE ovviamente.

    public static void main(java.lang.String[]) throws java.lang.Exception;
      descriptor: ([Ljava/lang/String;)V
      flags: ACC_PUBLIC, ACC_STATIC
      Code:
        stack=2, locals=2, args_size=1
           0: invokestatic  #2                  // Method returnsNull:()Ljava/lang/Boolean;
           3: invokevirtual #3                  // Method java/lang/Boolean.booleanValue:()Z
           6: invokestatic  #4                  // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
           9: astore_1
          10: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
          13: aload_1
          14: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
          17: return
        LineNumberTable:
          line 3: 0
          line 4: 10
          line 5: 17
      Exceptions:
        throws java.lang.Exception

    public static java.lang.Boolean returnsNull();
      descriptor: ()Ljava/lang/Boolean;
      flags: ACC_PUBLIC, ACC_STATIC
      Code:
        stack=1, locals=0, args_size=0
           0: aconst_null
           1: areturn
        LineNumberTable:
          line 8: 0



Links