Sono inciampato in uno strano NullPointerException
l'altro giorno causato da un cast di tipo imprevisto nell'operatore ternario. Data questa funzione (inutile esemplare):NullPointerException attraverso il comportamento di auto-boxing dell'operatore ternario Java
Integer getNumber() {
return null;
}
mi aspettavo seguenti due segmenti di codice di essere esattamente identica dopo la compilazione:
Integer number;
if (condition) {
number = getNumber();
} else {
number = 0;
}
vs.
Integer number = (condition) ? getNumber() : 0;
.
risulta, se condition
è true
, il if
-affermazione funziona bene, mentre l'opration ternario nel secondo segmento di codice lancia un NullPointerException
. Sembra che l'operazione ternaria abbia deciso di digitare entrambe le scelte su int
prima di reinserire automaticamente il risultato in un Integer
!?! Infatti, se lancio espressamente lo 0
su Integer
, l'eccezione scompare. In altre parole:
Integer number = (condition) ? getNumber() : 0;
non è lo stesso:
Integer number = (condition) ? getNumber() : (Integer) 0;
.
Quindi, sembra che ci sia una differenza di byte code tra l'operatore ternario e un equivalente if-else
-statement (qualcosa che non mi aspettavo). Il che solleva tre domande: perché c'è una differenza? Si tratta di un bug nell'implementazione ternaria o c'è una ragione per il tipo cast? Dato che c'è una differenza, l'operazione ternaria è più o meno performante di un equivalente if
-statement (lo so, la differenza non può essere enorme, ma comunque)?
Credi seriamente che c'è un errore nell'operatore ternario piuttosto che nella * comprensione * dell'uso documentato e delle restrizioni dell'operatore? Quali pensi che siano le probabilità di accadere realisticamente? Considera di cambiare il titolo della tua domanda in "incomprensione su come funziona l'operatore ternario". –
Ecco perché sto chiedendo alla domanda perché il compilatore decide che getNumber() e 0 devono entrambi valutare un int se assegno il risultato a un intero. Per me, non ha assolutamente senso gettare i due argomenti sul più restrittivo dei due tipi PRIMA del confronto piuttosto che sul tipo effettivamente richiesto DOPO il confronto. Perché passare attraverso unboxing e poi reboxing getNumber()? –
Non fa differenza ciò che tu o io riteniamo * debba * accadere. Piuttosto tutto ciò che conta è ciò che è chiaramente documentato nel JLS. –