Java NPE в тройном операторе с автобоксированием?

17

Сегодня утром я столкнулся с очень странным 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)
$
    
задан Kevin 18.10.2011 в 19:57
источник

5 ответов

29

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

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

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

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

    
ответ дан Jack Edmonds 18.10.2011 в 20:09
источник
3

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

return Integer.valueOf(item != null ? item.getId().intValue() : 1);
    
ответ дан smp7d 18.10.2011 в 20:08
источник
3

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

    
ответ дан nicholas.hauschild 18.10.2011 в 20:02
источник
2

Ниже приведен тип возврата 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, потому что пытается autobox null .

Попробуйте -

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

оба бросят NPE.

    
ответ дан Bhesh Gurung 18.10.2011 в 20:08
источник
2

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

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.

    
ответ дан AlexR 18.10.2011 в 20:11
источник