Dlaczego int num = Integer.getInteger („123”) zgłasza wyjątek NullPointerException?

106

Następujący kod generuje NullPointerException:

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

Czy mój kompilator wywołuje getIntegerwartość null, ponieważ jest statyczny? To nie ma sensu!

Co się dzieje?

user282886
źródło
3
zamiast tego użyj Integer.getValue (). Ten blog post jest dobry wyjaśnieniu dlaczego: konigsberg.blogspot.in/2008/04/...
Pranaysharma

Odpowiedzi:

212

Wielkie zdjęcie

Mamy tu do czynienia z dwoma problemami:

  • Integer getInteger(String) nie robi tego, co myślisz, że robi
    • W nulltym przypadku powraca
  • przypisanie od Integerdo intpowoduje automatyczne rozpakowywanie
    • Ponieważ Integerjest null, NullPointerExceptionjest rzucany

Do analizowania (String) "123"aby (int) 123można użyć np int Integer.parseInt(String).

Bibliografia

Integer Dokumentacja API


Na Integer.getInteger

Oto, co dokumentacja ma do powiedzenia na temat tego, co robi ta metoda:

public static Integer getInteger(String nm): Określa wartość całkowitą właściwości systemowej o określonej nazwie. Jeśli nie ma właściwości o określonej nazwie, jeśli określona nazwa jest pusta lub nulllub jeśli właściwość nie ma poprawnego formatu liczbowego, nullzwracana jest wartość.

Innymi słowy, ta metoda nie ma nic wspólnego z analizowaniem a Stringdo int/Integerwartości, a raczej z System.getPropertymetodą.

Trzeba przyznać, że może to być sporym zaskoczeniem. Szkoda, że ​​biblioteka ma takie niespodzianki, ale daje cenną lekcję: zawsze sprawdzaj dokumentację, aby potwierdzić, co robi metoda.

Zbiegiem okoliczności odmiana tego problemu została przedstawiona w prezentacji „ Return of the Puzzlers: Schlock and Awe (TS-5186)” , Josha Blocha i Neala Gaftera w 2009 roku w prezentacji JavaOne Technical Session. Oto slajd podsumowujący:

Morał

  • W bibliotekach czają się dziwne i straszne metody
    • Niektóre mają niewinnie brzmiące nazwiska
  • Jeśli twój kod źle się zachowuje
    • Upewnij się, że wywołujesz właściwe metody
    • Przeczytaj dokumentację biblioteki
  • Dla projektantów API
    • Nie naruszaj zasady najmniejszego zdziwienia
    • Nie naruszaj hierarchii abstrakcji
    • Nie używaj podobnych nazw dla bardzo różnych zachowań

Dla kompletności istnieją również te metody, które są analogiczne do Integer.getInteger:

Powiązane pytania


O autounboxingu

Inną kwestią jest oczywiście sposób NullPointerExceptionrzucania. Aby skupić się na tym problemie, możemy uprościć fragment w następujący sposób:

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

Oto cytat z Effective Java 2nd Edition, pozycja 49: Preferuj typy pierwotne od prymitywów pudełkowych:

Podsumowując, zawsze używaj prymitywów zamiast prymitywów pudełkowych, kiedy tylko masz wybór. Typy prymitywne są prostsze i szybsze. Jeśli musisz używać prymitywów w pudełkach, bądź ostrożny! Autoboxing zmniejsza szczegółowość, ale nie ogranicza niebezpieczeństwa używania pudełkowych prymitywów. Kiedy twój program porównuje dwa prymitywy w pudełku z ==operatorem, dokonuje porównania tożsamości, co prawie na pewno nie jest tym, czego chcesz. Kiedy twój program wykonuje obliczenia typu mieszanego z udziałem prymitywów zapakowanych i nieopakowanych, robi to rozpakowywanie, a kiedy twój program rozpakowuje, może rzucać NullPointerException. Wreszcie, gdy program zawiera prymitywne wartości, może to spowodować kosztowne i niepotrzebne tworzenie obiektów.

Są miejsca, w których nie masz innego wyboru, jak tylko użyć prymitywów pudełkowych, np. Generycznych, ale w przeciwnym razie powinieneś poważnie rozważyć, czy decyzja o użyciu prymitywów pudełkowych jest uzasadniona.

Powiązane pytania

smary wielogenowe
źródło
11
Więc Integer.getInteger(s)jest z grubsza równoważne Integer.parseInt(System.getProperty(s))? Myślę, że wolę drugą, chociaż jest bardziej rozwlekła, ponieważ podkreśla fakt, że pobierasz informacje z właściwości systemu.
MatrixFrog
5
Gdy tylko opublikowałem ten komentarz, zdałem sobie sprawę, że mogę po prostu spojrzeć na rzeczywiste źródło klasy Integer! Byłem na dobrej drodze, z wyjątkiem tego, że używa Integer.decodezamiast Integer.parseInt, który szuka wiodącego 0xlub 0analizuje liczbę odpowiednio jako szesnastkową lub ósemkową.
MatrixFrog
Dla tych, którzy pytają dlaczego NullPointerException? : programmers.stackexchange.com/questions/158908/ ...
ROMANIA_engineer
2
@Oracle Czy możesz wycofać java.lang.Integer.getInteger (String)?
mjaggard
6

Sprawdź dokumentację metody getInteger () . W tej metodzie Stringparametr jest właściwością systemową, która określa wartość całkowitą właściwości systemowej o określonej nazwie. Jak omówiono tutaj, „123” nie jest nazwą żadnej właściwości systemowej . Jeśli chcesz przekonwertować ten ciąg na int, użyj metody jako int num = Integer.parseInt("123").

Sonal Patil
źródło