Следующий код вызывает NullPointerException
:
int num = Integer.getInteger("123");
Является ли мой компилятор вызовом getInteger
на null, поскольку он статический? Это не имеет никакого смысла!
Что происходит?
Следующий код вызывает NullPointerException
:
int num = Integer.getInteger("123");
Является ли мой компилятор вызовом getInteger
на null, поскольку он статический? Это не имеет никакого смысла!
Что происходит?
Здесь есть две проблемы:
Integer getInteger(String)
не делает то, что, по вашему мнению, делает
null
в этом случаеInteger
до int
приводит к автоматическому распаковке
Integer
null
, NullPointerException
выбраноЧтобы разобрать (String) "123"
до (int) 123
, вы можете использовать, например. int Integer.parseInt(String)
.
Integer
Ссылки APIInteger.getInteger
Здесь, что документация должна сказать о том, что делает этот метод:
public static Integer getInteger(String nm)
: Определяет целочисленное значение системного свойства с указанным именем. Если свойство с указанным именем отсутствует, если указанное имя пуст илиnull
, или если свойство не имеет нужного числового формата, возвращаетсяnull
.
Другими словами, этот метод не имеет никакого отношения к разбору значения String
к значению int/Integer
, а скорее относится к System.getProperty
.
По общему признанию, это может быть весьма неожиданным. К сожалению, библиотека имеет такие сюрпризы, но она учит вас ценному уроку: всегда смотрите документацию, чтобы подтвердить, что делает метод.
В обоих случаях вариация этой проблемы была представлена в Возвращение головоломок: Шлока и Awe (TS-5186), Джош Блох и Нил Gafter 2009 JavaOne Техническая сессия. Здесь завершающий слайд:
Мораль
- Странные и ужасные методы скрываются в библиотеках
- У некоторых есть безобидные звуковые имена
- Если ваш код неверно работает
- Убедитесь, что вы вызываете правильные методы.
- Прочитайте документацию библиотеки
- Для разработчиков API
- Не нарушайте принцип наименьшего удивления.
- Не нарушать иерархию абстракции
- Не используйте похожие имена для совершенно разных поведений.
Для полноты существуют также эти методы, аналогичные Integer.getInteger
:
Другой проблемой, конечно же, является то, как бросается NullPointerException
. Чтобы сосредоточиться на этой проблеме, мы можем упростить фрагмент следующим образом:
Integer someInteger = null;
int num = someInteger; // throws NullPointerException!!!
Здесь цитата из Effective Java 2nd Edition, пункт 49: Предпочитают примитивные типы для примитивов в штучной упаковке:
В общем, используйте примитивы, предпочитая вложенные в бокс примитивы, когда у вас есть выбор. Примитивные типы проще и быстрее. Если вы должны использовать примитивы в штучной упаковке, будьте осторожны! Автобоксинг уменьшает многословие, но не опасность использования примитивов в штучной упаковке. Когда ваша программа сравнивает два вставных примитива с оператором
==
, это делает сравнение идентичности, которое почти наверняка не то, что вы хотите. Когда ваша программа выполняет смешанные вычисления с использованием примитивов с боксами и unboxed, она распаковывается, а когда ваша программа распаковывается, она может бросатьNullPointerException
. Наконец, когда ваши программные коды приносят примитивные значения, это может привести к дорогостоящим и ненужным созданиям объектов.
Есть места, где у вас нет выбора, кроме как использовать вставные примитивы, например. дженериков, но в противном случае вам следует серьезно подумать, оправдано ли решение использовать примитивы в штучной упаковке.
Из http://konigsberg.blogspot.com/2008/04/integergetinteger-are-you-kidding-me.html:
getInteger 'Определяет целочисленное значение системного свойства с указанным именем.'
Вы хотите:
Integer.parseInt("123")
Пожалуйста, проверьте документацию метода getInteger().
В этом методе параметр String
является системным свойством, которое определяет целочисленное значение системного свойства с указанным именем. "123" - это не имя какого-либо системного свойства, как обсуждалось здесь.
Если вы хотите преобразовать эту строку в int
, используйте метод как
int num = Integer.parseInt("123")
.