Java NPE в троичном операторе с автобоксом? - PullRequest
20 голосов
/ 18 октября 2011

Этим утром я наткнулся на очень странный NPE и сократил его до простого примера. Это ошибка JVM или правильное поведение?

public class Test1 {
    class Item {
        Integer id = null;
        public Integer getId() {return id;}
    }   
    public Integer f() {
        Item item = new Item();
        // this works:
        //return item == null ? new Integer(1) : item.getId();

        // NPE??
        return item == null ? 1 : item.getId();
    }   
    public static void main(String[] args) {
        Test1 t = new Test1();
        System.out.println("id is: " + String.valueOf(t.f()));
    }   
}

Вывод из компиляции и запуска:

$ javac Test1.java 
$ java Test1
Exception in thread "main" java.lang.NullPointerException
at Test1.f(Test1.java:12)
at Test1.main(Test1.java:16)
$

Ответы [ 5 ]

32 голосов
/ 18 октября 2011

Тип выражения item == null ? 1 : item.getId() - int, а не Integer. Поэтому Java необходимо автоматически распаковать ваш Integer в int (вызывая NullPointerException). Затем он автоматически упаковывает результат обратно в Integer (ну , если бы не NullPointerException) для возврата из метода.

С другой стороны, выражение item == null ? new Integer(1) : item.getId() имеет тип Integer, и автоматическая распаковка не требуется.

Когда вы автоматически распаковываете null Integer, вы получаете NullPointerException (см. Автобокс ), и это то, что вы испытываете.

Чтобы ответить на ваш вопрос, это правильное поведение.

3 голосов
/ 18 октября 2011

Если вы декомпилируете файл класса, вы ясно увидите свой NPE ...

return Integer.valueOf(item != null ? item.getId().intValue() : 1);
3 голосов
/ 18 октября 2011

item не может быть null, но при вызове getId() возвращается null Когда вы пытаетесь автоматически распаковать null, вы получаете NPE.

2 голосов
/ 18 октября 2011

Это происходит потому, что вы используете условный оператор ?. Линия

return item == null ? 1 : item.getId();

эквивалентно

int result = item == null ? 1 : item.getId();
return result;

Результат int из-за первого операнда в вашем выражении. Это причина того, что ваш код работает, когда вы явно заключаете 1 в Integer. В этом случае компилятор создает что-то вроде

Integer result = item == null ? new Integer(1) : item.getId();
return result;

Итак, NPE происходит при попытке "привести" item.getId () (который имеет значение null) к int.

2 голосов
/ 18 октября 2011

Тип возврата ниже Integer -

public Integer f() {
    Item item = new Item();
    // this works:
    //return item == null ? new Integer(1) : item.getId();

    // NPE??
    return item == null ? 1 : item.getId();
}

И результат следующий -

item == null ? 1 : item.getId()

- это null в вашем случае.

Итак, JVM выбрасывает NPE, потому что пытается автоматически поставить null.

Попробуйте -

new Integer(null); // and
Integer.valueOf(null);

оба бросят NPE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...