Почему int num = Integer.getInteger( "123" ) бросает NullPointerException?

Следующий код вызывает NullPointerException:

int num = Integer.getInteger("123");

Является ли мой компилятор вызовом getInteger на null, поскольку он статический? Это не имеет никакого смысла!

Что происходит?

Ответ 1

Большое изображение

Здесь есть две проблемы:

  • Integer getInteger(String) не делает то, что, по вашему мнению, делает
    • Он возвращает null в этом случае
  • назначение от Integer до int приводит к автоматическому распаковке
    • Так как Integer null, NullPointerException выбрано

Чтобы разобрать (String) "123" до (int) 123, вы можете использовать, например. int Integer.parseInt(String).

Ссылки

Integer Ссылки API


Вкл Integer.getInteger

Здесь, что документация должна сказать о том, что делает этот метод:

public static Integer getInteger(String nm): Определяет целочисленное значение системного свойства с указанным именем. Если свойство с указанным именем отсутствует, если указанное имя пуст или null, или если свойство не имеет нужного числового формата, возвращается null.

Другими словами, этот метод не имеет никакого отношения к разбору значения String к значению int/Integer, а скорее относится к System.getProperty.

По общему признанию, это может быть весьма неожиданным. К сожалению, библиотека имеет такие сюрпризы, но она учит вас ценному уроку: всегда смотрите документацию, чтобы подтвердить, что делает метод.

В обоих случаях вариация этой проблемы была представлена ​​в Возвращение головоломок: Шлока и Awe (TS-5186), Джош Блох и Нил Gafter 2009 JavaOne Техническая сессия. Здесь завершающий слайд:

Мораль

  • Странные и ужасные методы скрываются в библиотеках
    • У некоторых есть безобидные звуковые имена
  • Если ваш код неверно работает
    • Убедитесь, что вы вызываете правильные методы.
    • Прочитайте документацию библиотеки
  • Для разработчиков API
    • Не нарушайте принцип наименьшего удивления.
    • Не нарушать иерархию абстракции
    • Не используйте похожие имена для совершенно разных поведений.

Для полноты существуют также эти методы, аналогичные Integer.getInteger:

Связанные вопросы


В режиме autounbing

Другой проблемой, конечно же, является то, как бросается NullPointerException. Чтобы сосредоточиться на этой проблеме, мы можем упростить фрагмент следующим образом:

Integer someInteger = null;
int num = someInteger; // throws NullPointerException!!!

Здесь цитата из Effective Java 2nd Edition, пункт 49: Предпочитают примитивные типы для примитивов в штучной упаковке:

В общем, используйте примитивы, предпочитая вложенные в бокс примитивы, когда у вас есть выбор. Примитивные типы проще и быстрее. Если вы должны использовать примитивы в штучной упаковке, будьте осторожны! Автобоксинг уменьшает многословие, но не опасность использования примитивов в штучной упаковке. Когда ваша программа сравнивает два вставных примитива с оператором ==, это делает сравнение идентичности, которое почти наверняка не то, что вы хотите. Когда ваша программа выполняет смешанные вычисления с использованием примитивов с боксами и unboxed, она распаковывается, а когда ваша программа распаковывается, она может бросать NullPointerException. Наконец, когда ваши программные коды приносят примитивные значения, это может привести к дорогостоящим и ненужным созданиям объектов.

Есть места, где у вас нет выбора, кроме как использовать вставные примитивы, например. дженериков, но в противном случае вам следует серьезно подумать, оправдано ли решение использовать примитивы в штучной упаковке.

Связанные вопросы

Ответ 3

Пожалуйста, проверьте документацию метода getInteger(). В этом методе параметр String является системным свойством, которое определяет целочисленное значение системного свойства с указанным именем. "123" - это не имя какого-либо системного свойства, как обсуждалось здесь. Если вы хотите преобразовать эту строку в int, используйте метод как int num = Integer.parseInt("123").