2013-02-20 2 views
5

Если запустить следующий код,распаковка нулевого коробочный объекта бросает неожиданный NullPointerException

public class Foo{ 
    public static void main(String[] args){ 
     int id = new Bar().getId(); // throws unexpected NullPointerException 
    } 

    private static class Bar{ 
     private final Integer id; 

     public Bar(){ 
      this(null); 
     } 

     public Bar(Integer id){ 
      this.id = id; 
     } 

     public Integer getId(){ 
      return id; 
     } 
    } 
} 

вы получите следующую трассировку стеки,

Exception in thread "main" java.lang.NullPointerException 
    at Foo.main(Foo.java:3) 

Почему нет никакого предупреждения компилятора или что-нибудь? ИМХО, это довольно неприятная тонкость с распаковкой, или, может быть, я просто наивна.


Добавление к ответу, предоставленной @Javier, если вы используете Eclipse, вам нужно сделать следующее, чтобы включить это:

  1. Перейдите к Окно>предпочтения>Java>Компилятор>Ошибки/Предупреждения
  2. Expand Потенциальные проблемы программирования
  3. Переключить Упаковка и распаковка преобразования либо «Предупреждение» или «Ошибка»
  4. Нажмите «OK»
+0

Я не понимаю. Вы спрашиваете, почему происходит NPE, или это просто разглагольствование? Каким будет конкретный ответный вопрос? – madth3

ответ

5

Я не знаю, что IDE вы используете , но Eclipse имеет возможность включить предупреждение о боксах и распаковках конверсий. Невозможно обнаружить его как доступ к нулевому указателю, так как null не сразу распаковывается, а через Bar.getId().

Выражение типа Integer является Unboxed в ИНТ линии
Foo.java 3

+0

Я использую Eclipse в течение ~ 3 лет, и я этого не знал! Милая! – mre

+2

Это раздражает, что затмение не может включить unboxing предупреждения без бокса! https://bugs.eclipse.org/bugs/show_bug.cgi?id=163065 – Kyle

3

Если вы пытаетесь использовать любой метод на null или делать что-либо, что не имеет смысла с null, он выбрасывает NullPointerException.

Autounboxing реализуется с помощью метода [Integer object].intValue() (или аналогичного), поэтому он выбрасывает NullPointerException, потому что вы не можете использовать null метод.

Надеюсь, это поможет!

+1

+1 за этот бит о 'intValue' за кулисами, спасибо – mre

0

NullPointerException - RuntimeException, чем IDE не может обнаружить при компиляции кода.

Вместо этого хорошей практикой является проверка null перед распаковкой.

int getId(){ 
    if(id!=null){ 
     return id; 
    } 
    // return other or throw a checked exception. 
} 
0

Похоже, что это совершенно разумное исключение. Если ваш основной код был:

public static void main(String[] args){   
    Integer idObj = new Bar().getId(); 
    int id = idObj; // throws NullPointerException 
} 

Никто не удивился бы исключению нулевого указателя. Класс Bar возвращает null, а нулевой указатель объекта не может быть превращен в простое значение. Реализация класса Bar может быть изменена для инициализации id до ненулевого значения.Этот блок кода может быть скомпилирован независимо от класса Bar, поэтому предположения о динамической работе класса Bar не должны быть закодированы в этот блок кода.

Это, вероятно, очевидно, но настоящим решением является использование int для идентификатора, а не Integer. Это, то, не вопрос:

private static class Bar{ 
    private final int id; 

    public Bar(){ 
     this(0); 
    } 

    public Bar(int id){ 
     this.id = id; 
    } 

    public int getId(){ 
     return id; 
    } 
} 

(но я полагаю, вы уже знали об этом :-))

+0

Я не сказал, что исключение было необоснованным, я сказал, что это неожиданно, тем более, что моя IDE решила игнорировать его по умолчанию. – mre

+0

ОК, я пытался обойти «ожидаемые» и «неожиданные». Это исключение во время выполнения, а не то, что может быть обязательно определено из статического анализа. Как вы ожидаете, что IDE будет вести себя в этой ситуации? – AgilePro

+0

Я ожидал, что IDE по крайней мере предупредит меня по умолчанию. Как я уже сказал, я думаю, что это довольно тонкое исключение во время выполнения. – mre

4

представляется, что такое поведение документировано в JDK™ 5.0 Documentation,

.. вы можете в значительной степени игнорировать различие между int и Integer, с несколько оговорок. Выражение Integer может иметь нулевое значение. Если ваша программа пытается установить autounbox null, она выкинет NullPointerException.

0

Бокс - не более чем синтаксический сахар для придания объекту типа Integer к родному эквиваленту 'int'. Туземцы не могут быть пустыми, но объекты могут. Механизм бокса не будет препятствовать NullPointerExceptions в этих случаях.

Смежные вопросы