public class Npe {
static class Thing {
long value;
}
public static Map<Thing, Long> map;
public static void main(String[] args) {
Thing thing = new Thing();
method(null); // returns -1
method(thing); // returns 0
map = new HashMap<Thing, Long>();
method(null); // returns -1
method(thing); // NullPointerException thrown inside this method call
}
public static long method(Thing thing) {
if (thing == null) {
return -1;
}
Long v = (map == null) ? thing.value : map.get(thing); // NPE here
if (v == null) {
v = thing.value;
}
return v;
}
}
Al 4 ° chiamata a method()
ottengo un NullPointerException
gettato sulla linea indicata all'interno method()
. Se ho refactoring che la linea daPerché questo incarico causa NPE?
Long v = (map == null) ? thing.value : map.get(thing);
a
Long v;
if (map == null) {
v = thing.value;
} else {
v = map.get(thing);
}
non ottengo alcuna NullPointerException
e il metodo si comporta come dovrebbe. La domanda è: PERCHÉ ??
Sembra a me come il compilatore si aspetta il risultato dell'operatore ?
per essere long
in modo che sia unboxing automaticamente (l'abbassamento di livello da Long
al long
) il risultato della chiamata a map.get(thing)
(che può tornare null
e quindi lanciare un NullPointerException
). IMHO dovrebbe aspettarsi che il risultato dell'operatore ?
sia Long
e autoboxing (promozione di long
a Long
) thing.value
invece.
Ancora meglio, se mi refactoring questa dichiarazione:
Long v = (map == null) ? thing.value : map.get(thing);
a questo (casting long
a Long
esplicitamente):
Long v = (map == null) ? (Long)thing.value : map.get(thing);
mio IDE (IntelliJ) dice che il cast è ridondante, ma il codice compilato funziona come previsto e non genera uno NullPointerException
! :-D
possibile duplicato di [Booleani, operatori condizionali e autoboxing] (http://stackoverflow.com/questions/3882095/booleans-conditional-operators-and-autoboxing) –
@DwB Il tuo commento non è rilevante in quanto non sono un programmatore junior. E il tuo suggerimento di "non usare l'operatore ternario" è anche stupido. Solo perché qualcosa può essere complicato o confuso che non significa che non dovresti usarlo. Significa solo che devi stare attento e sapere cosa stai facendo. Se gli sviluppatori non avessero mai usato qualcosa di complicato o potenzialmente confuso, sarebbero stati tutti pittori o spazzini o giardinieri al posto dei programmatori ;-) –
Se non si capisce un operatore ternario, allora, che ci crediate o no, siete ancora junior con Giava. Inoltre, il fatto che qualcosa sia complicato, confuso e privo di valore è una buona ragione per non usarlo. Se gli sviluppatori non avessero mai usato qualcosa di complicato e potenzialmente confuso, avrebbero prodotto un codice meno complicato e confuso. – DwB