Zastanawiam się tylko, dlaczego instrukcja Java 7 switch
nie obsługuje null
przypadku i zamiast tego wyrzuca NullPointerException
? Zobacz skomentowaną linię poniżej (przykład zaczerpnięty z artykułu Java Tutorialsswitch
):
{
String month = null;
switch (month) {
case "january":
monthNumber = 1;
break;
case "february":
monthNumber = 2;
break;
case "march":
monthNumber = 3;
break;
//case null:
default:
monthNumber = 0;
break;
}
return monthNumber;
}
Pozwoliłoby to uniknąć if
warunku zerowego sprawdzania przed każdym switch
użyciem.
java
switch-statement
language-design
Prashant Bhate
źródło
źródło
null
spowoduje wyjątek. Wykonaćif
czeknull
, a następnie przejść doswitch
zestawienia.NullPointerException
jeśli wyrażenie ma wartośćnull
w czasie wykonywania] jest lepszym wynikiem niż ciche pomijanie całej instrukcji switch lub wybieranie wykonania instrukcji (jeśli istnieją) po etykieta domyślna (jeśli istnieje).Odpowiedzi:
Jak wskazuje damryfbfnetsi w komentarzach, JLS §14.11 ma następującą uwagę:
(podkreślenie moje)
Chociaż ostatnie zdanie pomija możliwość użycia
case null:
, wydaje się rozsądne i daje wgląd w intencje projektantów języka.Jeśli wolimy spojrzeć na szczegóły implementacji, ten post na blogu Christiana Hujera zawiera wnikliwe spekulacje na temat tego, dlaczego
null
nie jest to dozwolone w przełącznikach (chociaż koncentruje się naenum
przełączniku, a nie naString
przełączniku):Chociaż
String
przełączniki są implementowane w różny sposób ,enum
przełącznik pojawił się jako pierwszy i ustawił precedens dotyczący tego, jak powinno zachowywać się włączenie typu odniesienia, gdy jest to odniesienienull
.źródło
case null:
gdyby został zaimplementowany na wyłączność, byłoby dużym usprawnieniemString
. Obecnie wszystkieString
sprawdzania wymagają sprawdzenia zerowego, jeśli chcemy to zrobić poprawnie, chociaż głównie niejawnie, umieszczając najpierw stałą łańcuchową, jak in"123test".equals(value)
. Teraz jesteśmy zmuszeni napisać nasze oświadczenie o przełączniku, jak wif (value != null) switch (value) {...
Ogólnie
null
jest nieprzyjemny w obsłudze; może bez lepszego języka da się żyćnull
.Twój problem może zostać rozwiązany przez
źródło
month
jest to pusty ciąg: potraktuje to tak samo, jak łańcuch pusty.Nie jest ładny, ale
String.valueOf()
pozwala na użycie zerowego ciągu w przełączniku. Jeśli znajdzienull
, konwertuje go na"null"
, w przeciwnym razie po prostu zwraca ten sam ciąg, który go przekazałeś. Jeśli nie poradzisz sobie"null"
bezpośrednio, przejdzie dodefault
. Jedynym zastrzeżeniem jest to, że nie ma sposobu na rozróżnienie między String"null"
a rzeczywistąnull
zmienną.źródło
To próba odpowiedzi, dlaczego rzuca
NullPointerException
Dane wyjściowe poniższego polecenia javap ujawniają, że
case
jest ono wybierane na podstawie kodu skrótuswitch
ciągu argumentu i dlatego rzuca NPE, gdy.hashCode()
jest wywoływane na łańcuchu zerowym.Oznacza to, w oparciu o odpowiedzi na pytanie Czy kod hashCode języka Java może generować tę samą wartość dla różnych ciągów? , choć rzadko, nadal istnieje możliwość dopasowania dwóch przypadków (dwa ciągi znaków z tym samym kodem skrótu) Zobacz poniższy przykład
javap dla którego
Jak widać, generowany jest tylko jeden przypadek
"Ea"
, a"FB"
jednak z dwóchif
warunków, aby sprawdzić na mecz z każdym przypadku łańcucha. Bardzo ciekawy i skomplikowany sposób implementacji tej funkcjonalności!źródło
hashCode
zwracaniu tych samych wartości w różnych uruchomieniach programu, ale ponieważ skróty ciągów są upieczone w plikach wykonywalnych przez kompilator, metoda skrótu napisów kończy się jako część specyfikacji języka.Krótko mówiąc ... (i miejmy nadzieję, że wystarczająco interesujące !!!)
Enum zostały po raz pierwszy wprowadzone w Javie 1.5 ( wrzesień 2004 ), a błąd żądający zezwolenia na włączenie String został zgłoszony dawno temu ( październik 1995 ). Jeśli spojrzysz na komentarz opublikowany na temat tego błędu w czerwcu 2004 , mówi, że
Don't hold your breath. Nothing resembling this is in our plans.
wygląda na to, że odroczyli ( zignorowali ) ten błąd i ostatecznie uruchomili Javę 1.5 w tym samym roku, w którym wprowadzili 'wyliczenie' z liczbą porządkową zaczynającą się od 0 i zdecydowali ( brakowało ), aby nie obsługiwać wartości null dla wyliczenia. Później w Javie 1.7 ( lipiec 2011 ) poszli za nim ( wymuszeni) ta sama filozofia co w przypadku String (tj. podczas generowania kodu bajtowego nie przeprowadzono sprawdzenia wartości null przed wywołaniem metody hashcode ()).Więc myślę, że sprowadza się to do faktu, że wyliczenie pojawiło się jako pierwsze i zostało zaimplementowane z początkiem porządkowym od 0, przez co nie mogli obsługiwać wartości null w bloku przełącznika, a później z String postanowili wymusić tę samą filozofię, tj. Wartość null nie dozwolone w bloku przełączników.
TL; DR Dzięki String mogliby zająć się NPE (spowodowanym próbą wygenerowania hashcode dla null) podczas implementacji kodu java do konwersji kodu bajtowego, ale ostatecznie zdecydowali się tego nie robić.
Ref: TheBUG , JavaVersionHistory , JavaCodeToByteCode , SO
źródło
Według Java Docs:
Ponieważ
null
nie ma typu i nie jest instancją niczego, nie będzie działać z instrukcją switch.źródło
null
jest prawidłową wartością dlaString
,Character
,Byte
,Short
, lubInteger
odniesienia.Odpowiedź jest prosta, jeśli użyjesz przełącznika z typem referencyjnym (takim jak typ pierwotny pudełkowy), błąd czasu wykonania wystąpi, jeśli wyrażenie jest puste, ponieważ rozpakowanie go wyrzuci NPE.
więc case null (co jest nielegalne) i tak nigdy nie mogłoby zostać wykonane;)
źródło
if (x == null) { // the case: null part }
Zgadzam się z wnikliwymi komentarzami (Under the hood…) w https://stackoverflow.com/a/18263594/1053496 w odpowiedzi @Paul Bellora.
Z własnego doświadczenia znalazłem jeszcze jeden powód.
Jeśli „przypadek” może mieć wartość null, co oznacza, że przełącznik (zmienna) jest pusty, to tak długo, jak programista dostarcza pasującą wielkość „null”, możemy argumentować, że jest w porządku. Ale co się stanie, jeśli programista nie poda żadnego pasującego przypadku „zerowego”. Następnie musimy dopasować to do „domyślnego” przypadku, który może nie być tym, co programista zamierzał obsłużyć w domyślnym przypadku. Dlatego dopasowanie wartości „null” do wartości domyślnej może spowodować „zaskakujące zachowanie”. Dlatego rzucenie 'NPE' zmusi programistę do obsługi każdego przypadku jawnie. Uważam, że rzucanie NPE w tym przypadku jest bardzo przemyślane.
źródło
Użyj klasy Apache StringUtils
źródło