Boolean.valueOf() иногда создает исключение NullPointerException
У меня есть этот код:
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
), между тем тест 4 бросает a NullPointerException
. Как вы можете видеть в тестах 1 и 2, null
и modifiedItems.get("item1")
равны и null
.
Поведение одинаково в Java 7 и 8.
Ответы
Ответ 1
Вам нужно внимательно посмотреть, на что вызывается перегрузка:
-
Boolean.valueOf(null)
вызывает Boolean.valueOf(String)
. Это не бросает NPE
, даже если поставляется с нулевым параметром.
-
Boolean.valueOf(modifiedItems.get("item1"))
вызывает Boolean.valueOf(boolean)
, потому что значения modifiedItems
имеют тип Boolean
, для которого требуется преобразование unboxing. Так как modifiedItems.get("item1")
null
, то это unboxing этого значения, а не Boolean.valueOf(...)
, который выбрасывает NPE.
Правила определения того, какая перегрузка вызывается, довольно волосатые, но они примерно идут следующим образом:
-
В первом проходе выполняется поиск совпадения методов без разрешения метода бокса/распаковки (или методов переменной arity).
- Поскольку
null
является допустимым значением для String
, но не Boolean
, Boolean.valueOf(null)
соответствует этому значению Boolean.valueOf(String)
;
-
Boolean
не является приемлемым ни для Boolean.valueOf(String)
, ни для Boolean.valueOf(boolean)
, поэтому в этом проходе для Boolean.valueOf(modifiedItems.get("item1"))
не указан ни один метод.
-
Во втором проходе выполняется поиск метода, позволяющий использовать методы бокса/распаковки (но все же не переменные arity).
- A
Boolean
может быть распакован на Boolean
, поэтому Boolean.valueOf(boolean)
соответствует этому значению Boolean.valueOf(modifiedItems.get("item1"))
; но компилятор должен вставлять преобразование unboxing для его вызова: Boolean.valueOf(modifiedItems.get("item1").booleanValue())
-
(Там третий проход, позволяющий использовать методы переменной arity, но который здесь не уместен, поскольку первые два прохода соответствуют этим случаям)
Ответ 2
Так как modifiedItems.get
возвращает Boolean
(который не применим к String
), сигнатура, которая будет использоваться, Boolean.valueOf(boolean)
, где Boolean
переименовывается в примитив Boolean
. Как только null
возвращается туда, сбой при исходящей передаче с NullPointerException
.
Ответ 3
Подпись метода
Метод Boolean.valueOf(...)
имеет две подписи:
-
public static Boolean valueOf(boolean b)
-
public static Boolean valueOf(String s)
Значение modifiedItems
Boolean
. Вы не можете отбрасывать Boolean
до String
, поэтому, следовательно, будет выбрана первая подпись
Логическое распаковка
В вашем заявлении
Boolean.valueOf(modifiedItems.get("item1"))
который можно прочитать как
Boolean.valueOf(modifiedItems.get("item1").booleanValue())
Однако modifiedItems.get("item1")
возвращает null
, поэтому у вас будет
null.booleanValue()
что, очевидно, приводит к a NullPointerException
Ответ 4
Поскольку Энди уже очень хорошо описал причину NullPointerException
:
что связано с булевым un-боксом:
Boolean.valueOf(modifiedItems.get("item1"))
преобразуется в:
Boolean.valueOf(modifiedItems.get("item1").booleanValue())
во время выполнения, а затем он бросает NullPointerException
, если modifiedItems.get("item1")
имеет значение null.
Теперь я хотел бы добавить еще одну мысль о том, что un-бокс следующих классов в их соответствующие примитивы также может генерировать исключение NullPointerException
, если их соответствующие возвращенные объекты равны нулю.
- byte - Byte
- char - Персонаж
- float - Float
- int - Integer
- long - Long
- short - Short
- double - Double
Вот код:
Hashtable<String, Boolean> modifiedItems1 = new Hashtable<String, Boolean>();
System.out.println(Boolean.valueOf(modifiedItems1.get("item1")));//Exception in thread "main" java.lang.NullPointerException
Hashtable<String, Byte> modifiedItems2 = new Hashtable<String, Byte>();
System.out.println(Byte.valueOf(modifiedItems2.get("item1")));//Exception in thread "main" java.lang.NullPointerException
Hashtable<String, Character> modifiedItems3 = new Hashtable<String, Character>();
System.out.println(Character.valueOf(modifiedItems3.get("item1")));//Exception in thread "main" java.lang.NullPointerException
Hashtable<String, Float> modifiedItems4 = new Hashtable<String, Float>();
System.out.println(Float.valueOf(modifiedItems4.get("item1")));//Exception in thread "main" java.lang.NullPointerException
Hashtable<String, Integer> modifiedItems5 = new Hashtable<String, Integer>();
System.out.println(Integer.valueOf(modifiedItems5.get("item1")));//Exception in thread "main" java.lang.NullPointerException
Hashtable<String, Long> modifiedItems6 = new Hashtable<String, Long>();
System.out.println(Long.valueOf(modifiedItems6.get("item1")));//Exception in thread "main" java.lang.NullPointerException
Hashtable<String, Short> modifiedItems7 = new Hashtable<String, Short>();
System.out.println(Short.valueOf(modifiedItems7.get("item1")));//Exception in thread "main" java.lang.NullPointerException
Hashtable<String, Double> modifiedItems8 = new Hashtable<String, Double>();
System.out.println(Double.valueOf(modifiedItems8.get("item1")));//Exception in thread "main" java.lang.NullPointerException
Ответ 5
Способ понять это, когда вызывается Boolean.valueOf(null)
, java точно сказывается для вычисления нулевого значения.
Однако, когда вызывается Boolean.valueOf(modifiedItems.get("item1"))
, java говорят, чтобы получить значение из HashTable типа объекта Boolean, но он не находит тип Boolean, он находит тупик вместо (null), хотя он ожидал, что Boolean, Исключение NullPointerException выбрано потому, что создатели этой части java решили, что эта ситуация является примером того, что в программе происходит неправильно, что требует внимания программиста. (Произошло что-то непредвиденное.)
В этом случае разница между сознательным объявлением о том, что вы намереваетесь указать нуль, и java, обнаруживает недостающую ссылку на объект (нуль), где должен был быть найден объект.
Дополнительную информацию о NullPointerException в этом ответе:
fooobar.com/info/55263/...