У меня есть такой код:
package tests;
import java.util.Hashtable;
public class Tests {
public static void main(String[] args) {
Hashtable<String, Boolean> modifiedItems = new Hashtable<String, Boolean>();
System.out.println("TEST 1");
System.out.println(modifiedItems.get("item1")); // Prints null
System.out.println("TEST 2");
System.out.println(modifiedItems.get("item1") == null); // Prints true
System.out.println("TEST 3");
System.out.println(Boolean.valueOf(null)); // Prints false
System.out.println("TEST 4");
System.out.println(Boolean.valueOf(modifiedItems.get("item1"))); // Produces NullPointerException
System.out.println("FINISHED!"); // Never executed
}
}
Моя проблема в том, что я не понимаю, почему Test 3 работает нормально (печатает false
и не производит NullPointerException
), в то время как Test 4 выдает ошибку NullPointerException
. Как видно из тестов 1 и 2 , null
и modifiedItems.get("item1")
равны и null
.
То же самое в Java 7 и 8.
java
nullpointerexception
boolean
Дэвид Э
источник
источник
null
и той же функции , не генерируется NPE! Для этого есть веская причина, но это определенно сбивает с толку на первый взгляд :-)==
применяется.Ответы:
Вы должны внимательно посмотреть, какая перегрузка вызывается:
Boolean.valueOf(null)
вызываетBoolean.valueOf(String)
. Это не вызывает,NPE
даже если передано с нулевым параметром.Boolean.valueOf(modifiedItems.get("item1"))
вызываетBoolean.valueOf(boolean)
, потому чтоmodifiedItems
значения имеют типBoolean
, который требует преобразования распаковки. ТакmodifiedItems.get("item1")
какnull
это распаковка этого значения, а не самого,Boolean.valueOf(...)
вызывает NPE.Правила определения того, какая перегрузка вызывается, довольно сложны , но примерно так:
На первом проходе ищется соответствие метода без разрешения упаковки / распаковки (а также методов переменной арности).
null
является допустимым значением для ,String
но неboolean
,Boolean.valueOf(null)
согласованBoolean.valueOf(String)
в этом проходе;Boolean
не является приемлемым для любойBoolean.valueOf(String)
илиBoolean.valueOf(boolean)
, так что ни один метод не согласован в этом проходе дляBoolean.valueOf(modifiedItems.get("item1"))
.Во втором проходе ищется соответствие метода, что позволяет упаковывать / распаковывать (но все же не методы переменной арности).
Boolean
может быть распакованboolean
, поэтомуBoolean.valueOf(boolean)
соответствуетBoolean.valueOf(modifiedItems.get("item1"))
в этом проходе; но преобразование распаковки должно быть вставлено компилятором, чтобы вызвать его:Boolean.valueOf(modifiedItems.get("item1").booleanValue())
(Есть третий проход, позволяющий использовать методы переменной арности, но здесь это не актуально, поскольку первые два прохода соответствовали этим случаям)
источник
Boolean.valueOf(modifiedItems.get("item1").booleanValue())
в исходном коде вместоBoolean.valueOf(modifiedItems.get("item1"))
?.booleanValue()
в выражении. Два наблюдения: 1) автоматическое (снятие) боксов - это преднамеренная функция Java для устранения синтаксического мусора; сделать это самому можно, но не идиоматично; 2) это вам совсем не помогает - это, конечно, не останавливает возникновение проблемы и не дает дополнительной информации, когда происходит сбой (трассировка стека будет идентична, потому что выполняемый код идентичен).Поскольку
modifiedItems.get
возвращаетBoolean
(что не колдовать кString
), подпись , которая будет использоваться вBoolean.valueOf(boolean)
, гдеBoolean
находится перебоксировал к примитивнымboolean
. Послеnull
возврата туда исходящие сообщения завершаются с ошибкойNullPointerException
.источник
Подпись метода
У метода
Boolean.valueOf(...)
две сигнатуры:public static Boolean valueOf(boolean b)
public static Boolean valueOf(String s)
Ваша
modifiedItems
ценностьBoolean
. Вы не можетеBoolean
выполнить кастинг,String
поэтому будет выбрана первая подписьБулево распаковка
В вашем заявлении
что можно прочитать как
Однако
modifiedItems.get("item1")
возвращается,null
так что в основном у вас будетчто, очевидно, приводит к
NullPointerException
источник
Как уже очень хорошо описал Энди причину
NullPointerException
:что связано с булевой распаковкой:
преобразоваться в:
во время выполнения, а затем бросает,
NullPointerException
еслиmodifiedItems.get("item1")
имеет значение null.Теперь я хотел бы добавить здесь еще один момент, что распаковка следующих классов в их соответствующие примитивы также может вызвать
NullPointerException
исключение, если их соответствующие возвращаемые объекты равны нулю.Вот код:
источник
Способ понять, что это когда
Boolean.valueOf(null)
вызывается, java точно сообщает, что нужно оценить значение null.Однако при
Boolean.valueOf(modifiedItems.get("item1"))
вызове java предлагается получить значение из HashTable типа объекта Boolean, но он не находит тип Boolean, а вместо этого находит тупик (null), хотя ожидал Boolean. Исключение NullPointerException выбрасывается, потому что создатели этой части java решили, что эта ситуация является примером того, что в программе что-то идет не так, что требует внимания программиста. (Произошло что-то непреднамеренное.)В этом случае это больше разница между преднамеренным заявлением о том, что вы намеревались иметь нулевое значение, и обнаружением java отсутствующей ссылки на объект (null), где объект должен был быть найден.
Дополнительную информацию о NullPointerException см. В этом ответе: https://stackoverflow.com/a/25721181/4425643
источник