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;
}
}
На 4-м вызове method()
я получаю a NullPointerException
, сброшенную по указанной строке внутри method()
. Если я реорганизую эту строку из
Long v = (map == null) ? thing.value : map.get(thing);
к
Long v;
if (map == null) {
v = thing.value;
} else {
v = map.get(thing);
}
Я не получаю NullPointerException
, и метод ведет себя так, как должен. Вопрос: ПОЧЕМУ?
Мне кажется, что компилятор ожидает, что результатом оператора ?
будет long
, чтобы он автоматически распаковывал (понижая с long
до long
) результат вызова map.get(thing)
(который может возвращать null
и, следовательно, бросать a NullPointerException
). ИМХО, следует ожидать, что результатом оператора ?
будет long
и автобоксинга (вместо long
to long
) thing.value
.
Еще лучше, если я реорганизую это утверждение:
Long v = (map == null) ? thing.value : map.get(thing);
к этому (явно отбрасывая long
до long
):
Long v = (map == null) ? (Long)thing.value : map.get(thing);
моя IDE (IntelliJ) говорит, что листинг является избыточным, но скомпилированный код работает так, как ожидалось, и не бросает NullPointerException
!:-D