Używam object != null
dużo, aby tego uniknąć NullPointerException
.
Czy jest na to dobra alternatywa?
Na przykład często używam:
if (someobject != null) {
someobject.doCalc();
}
To sprawdza czy NullPointerException
dla someobject
obiektu w powyższym fragmencie.
Należy pamiętać, że zaakceptowana odpowiedź może być nieaktualna, najnowsze https://stackoverflow.com/a/2386013/12943 .
java
object
nullpointerexception
null
Goran Martinic
źródło
źródło
Option
typ Scali jest zniekształcony niechęcią języka do kontrolowania lub odrzucanianull
. Wspomniałem o tym na hackernews i przegłosowałem i powiedziałem, że „nikt nie używa null w Scali”. Zgadnij co, już znajduję wartości zerowe w napisanej przez współpracownika Scali. Tak, „robią to źle” i trzeba o tym wiedzieć, ale faktem jest, że system typów językowych powinien mnie przed tym chronić, a tak nie jest :(Odpowiedzi:
Wydaje mi się, że to dość powszechny problem, z którym w pewnym momencie spotykają się programiści od młodszych do średniozaawansowanych: albo nie znają kontraktów, w których uczestniczą, ani nie ufają im, i defensywnie sprawdzają zerowe wartości. Dodatkowo, podczas pisania własnego kodu, zwykle polegają na zwracaniu wartości null w celu wskazania czegoś, co wymaga od dzwoniącego sprawdzenia wartości null.
Innymi słowy, istnieją dwa przypadki, w których pojawia się sprawdzanie wartości NULL:
Gdzie null jest prawidłową odpowiedzią w odniesieniu do umowy; i
Gdzie nie jest to prawidłowa odpowiedź.
(2) jest łatwe. Użyj
assert
instrukcji (twierdzeń) lub zezwól na niepowodzenie (na przykład NullPointerException ). Asercje to wysoce niewykorzystana funkcja Java, która została dodana w wersji 1.4. Składnia jest następująca:lub
gdzie
<condition>
jest wyrażeniem logicznym i<object>
jest obiektem, którego wyniktoString()
metody zostanie uwzględniony w błędzie.assert
Oświadczenie wyrzucaError
(AssertionError
) jeśli warunek nie jest prawdą. Domyślnie Java ignoruje twierdzenia. Można włączyć asercje, przekazując opcję-ea
do JVM. Możesz włączać i wyłączać asercje dla poszczególnych klas i pakietów. Oznacza to, że możesz sprawdzać poprawność kodu z asercjami podczas opracowywania i testowania oraz wyłączać je w środowisku produkcyjnym, chociaż moje testy wykazały prawie żaden wpływ na wydajność z asercji.Nieużywanie asercji w tym przypadku jest OK, ponieważ kod po prostu się nie powiedzie, co stanie się, jeśli użyjesz asercji. Jedyną różnicą jest to, że w przypadku stwierdzeń może się to zdarzyć wcześniej, w bardziej znaczący sposób i być może z dodatkowymi informacjami, które mogą pomóc ci dowiedzieć się, dlaczego tak się stało, jeśli się tego nie spodziewałeś.
(1) jest trochę trudniejszy. Jeśli nie masz kontroli nad kodem, który dzwonisz, utkniesz. Jeśli null jest prawidłową odpowiedzią, musisz ją sprawdzić.
Jeśli jednak kontrolujesz kod (i często tak się dzieje), to inna historia. Unikaj używania wartości null jako odpowiedzi. Dzięki metodom, które zwracają kolekcje, jest to łatwe: zwracaj puste kolekcje (lub tablice) zamiast prawie zer.
W przypadku braku kolekcji może być trudniej. Rozważ to jako przykład: jeśli masz te interfejsy:
gdzie Parser pobiera dane wejściowe od użytkownika i znajduje coś do zrobienia, być może, jeśli implementujesz interfejs wiersza poleceń. Teraz możesz sprawić, że umowa zwróci wartość zerową, jeśli nie zostaną podjęte odpowiednie działania. To prowadzi do sprawdzenia zerowego, o którym mówisz.
Alternatywnym rozwiązaniem jest nigdy nie zwracać wartości null, a zamiast tego używać wzorca Null Object :
Porównać:
do
co jest znacznie lepszym projektem, ponieważ prowadzi do bardziej zwięzłego kodu.
To powiedziawszy, być może jest całkowicie właściwe, aby metoda findAction () zgłosiła wyjątek z sensownym komunikatem o błędzie - szczególnie w tym przypadku, gdy polegasz na danych wejściowych użytkownika. O wiele lepiej byłoby, gdyby metoda findAction zgłosiła wyjątek, niż metoda wywołująca wysadzenie prostego wyjątku NullPointerException bez wyjaśnienia.
Lub jeśli uważasz, że mechanizm try / catch jest zbyt brzydki, zamiast nic nie rób, domyślna akcja powinna dostarczyć użytkownikowi informacji zwrotnej.
źródło
Jeśli używasz (lub planujesz użyć) środowiska Java IDE, takiego jak JetBrains IntelliJ IDEA , Eclipse lub Netbeans, lub narzędzia takiego jak findbugs, możesz użyć adnotacji, aby rozwiązać ten problem.
Zasadniczo masz
@Nullable
i@NotNull
.Możesz użyć metody i parametrów, takich jak to:
lub
Drugi przykład nie zostanie skompilowany (w IntelliJ IDEA).
Gdy użyjesz pierwszej
helloWorld()
funkcji w innym fragmencie kodu:Teraz kompilator IntelliJ IDEA powie ci, że sprawdzenie jest bezużyteczne, ponieważ
helloWorld()
funkcja nigdy nie powrócinull
.Za pomocą parametru
jeśli napiszesz coś takiego:
To się nie skompiluje.
Ostatni przykład użycia
@Nullable
Robiąc to
I możesz być pewien, że tak się nie stanie. :)
To dobry sposób, aby pozwolić kompilatorowi sprawdzić coś więcej niż zwykle i wymusić silniejsze kontrakty. Niestety nie jest obsługiwany przez wszystkie kompilatory.
W IntelliJ IDEA 10.5 i nowszych dodano obsługę wszystkich innych
@Nullable
@NotNull
implementacji.Zobacz wpis na blogu Bardziej elastyczne i konfigurowalne adnotacje @ Nullable / @ NotNull .
źródło
@NotNull
,@Nullable
a inne adnotacje o nieważności są częścią JSR 305 . Możesz ich również użyć do wykrycia potencjalnych problemów z narzędziami takimi jak FindBugs .@NotNull
i znajdują się@Nullable
w pakieciecom.sun.istack.internal
. (Chyba kojarzę com.sun z ostrzeżeniami o używaniu zastrzeżonego API).@NotNull
i@Nullable
są to, że ładnie pogorszyć, gdy kod źródłowy jest zbudowany przez system, który ich nie rozumieją. W rezultacie argument, że kod nie jest przenośny, może być nieprawidłowy - jeśli używasz systemu, który obsługuje i rozumie te adnotacje, zyskujesz dodatkową korzyść z bardziej rygorystycznego sprawdzania błędów, w przeciwnym razie dostajesz mniej, ale kod nadal powinien zbuduj dobrze, a jakość twojego programu działa TAKIE SAMO, ponieważ te adnotacje i tak nie zostały wymuszone w czasie wykonywania. Poza tym wszystkie kompilatory są niestandardowe ;-)Jeśli wartości zerowe są niedozwolone
Jeśli twoja metoda jest wywoływana zewnętrznie, zacznij od czegoś takiego:
Następnie, w pozostałej części tej metody, będziesz wiedział, że
object
nie jest zerowa.Jeśli jest to metoda wewnętrzna (nie jest częścią interfejsu API), po prostu udokumentuj, że nie może być pusta i to wszystko.
Przykład:
Jeśli jednak twoja metoda przekazuje wartość, a następna metoda przekazuje ją itd., Może to powodować problemy. W takim przypadku możesz sprawdzić argument jak wyżej.
Jeśli dozwolone jest zero
To naprawdę zależy. Jeśli okaże się, że często robię coś takiego:
Więc rozgałęziam się i robię dwie zupełnie różne rzeczy. Nie ma brzydkiego fragmentu kodu, ponieważ naprawdę muszę zrobić dwie różne rzeczy w zależności od danych. Na przykład, czy powinienem pracować na danych wejściowych, czy powinienem obliczyć dobrą wartość domyślną?
W rzeczywistości rzadko używam idiomu „
if (object != null && ...
”.Podanie przykładów może być łatwiejsze, jeśli pokażesz przykłady tego, gdzie zazwyczaj używasz tego idiomu.
źródło
throw new IllegalArgumentException("object==null")
Wow, prawie nienawidzę dodawać kolejnej odpowiedzi, gdy mamy 57 różnych sposobów na zarekomendowanie
NullObject pattern
, ale myślę, że niektórzy ludzie zainteresowani tym pytaniem mogą wiedzieć, że na stole jest propozycja dodania Java 7 „zerowo bezpieczna” handling ” - usprawniona składnia dla logiki „ jeśli nie jest równa zeru ”.Przykład podany przez Alexa Millera wygląda następująco:
Te
?.
środki tylko de referencyjne lewy identyfikator, jeśli nie jest null, inaczej ocenić pozostałą część wyrazu jaknull
. Niektórzy ludzie, jak członek Javy Posse, Dick Wall i wyborcy w Devoxx, naprawdę uwielbiają tę propozycję, ale jest też sprzeciw, ponieważ faktycznie zachęca do większego wykorzystanianull
jako wartownika.Aktualizacja: oficjalna propozycja dla null-safe operatora w Java 7 został złożony w ramach Projektu Coin. Składnia jest nieco inna niż w powyższym przykładzie, ale to samo pojęcie.
Aktualizacja: Oferta operatora zerowo bezpieczna nie trafiła do monety projektu. Tak więc nie zobaczysz tej składni w Javie 7.
źródło
Jeśli niezdefiniowane wartości nie są dozwolone:
Możesz skonfigurować swoje IDE, aby ostrzegało przed potencjalnym zerowym odwołaniem. Np. W Eclipse, zobacz Preferencje> Java> Kompilator> Błędy / Ostrzeżenia / Analiza zerowa .
Jeśli dozwolone są niezdefiniowane wartości:
Jeśli chcesz zdefiniować nowy interfejs API, w którym sens mają niezdefiniowane wartości , użyj Wzorca Opcji (może być znany z języków funkcjonalnych). Ma następujące zalety:
Java 8 ma wbudowaną
Optional
klasę (zalecane); dla wcześniejszych wersji, istnieją alternatywy biblioteki, na przykład Guava „sOptional
lub FunctionalJava ” sOption
. Ale podobnie jak wiele funkcjonalnych wzorców, użycie Option w Javie (nawet 8) daje całkiem spory przykład, który można zredukować, używając mniej szczegółowego języka JVM, np. Scala lub Xtend.Jeśli masz do czynienia z interfejsem API, który może zwracać wartości zerowe , nie możesz wiele zrobić w Javie. Xtend i Groovy mają operator Elvisa
?:
i operator wyzerowania bezpieczny dla wartości zerowych?.
, ale należy pamiętać, że to zwraca wartość zerową w przypadku odwołania zerowego, więc po prostu „odracza” prawidłowe zarządzanie wartością zerową.źródło
Tylko w tej sytuacji -
Nie sprawdzanie, czy zmienna ma wartość null przed wywołaniem metody równości (przykład porównania ciągów poniżej):
spowoduje, że
NullPointerException
iffoo
nie istnieje.Możesz tego uniknąć, porównując swoje w
String
ten sposób:źródło
<object that you know that is not null>.equals(<object that might be null>);
. Działa dla innych metod niż teequals
, które znasz z kontraktu i te metody mogą obsługiwaćnull
parametry.Wraz z Javą 8 pojawia się nowa
java.util.Optional
klasa, która prawdopodobnie rozwiązuje część problemu. Można przynajmniej powiedzieć, że poprawia to czytelność kodu, aw przypadku publicznych interfejsów API uczynić umowę API bardziej przejrzystą dla programisty klienta.Działają w ten sposób:
Obiekt opcjonalny dla danego typu (
Fruit
) jest tworzony jako typ zwracany przez metodę. Może być pusty lub zawieraćFruit
obiekt:Teraz spójrz na ten kod, w którym przeszukujemy listę
Fruit
(fruits
) dla danej instancji Fruit:Za pomocą
map()
operatora można wykonać obliczenia na - lub wyodrębnić wartość - z opcjonalnego obiektu.orElse()
pozwala zapewnić rezerwę na brakujące wartości.Oczywiście sprawdzenie wartości pustej / pustej jest nadal konieczne, ale przynajmniej deweloper ma świadomość, że wartość może być pusta, a ryzyko zapomnienia o sprawdzeniu jest ograniczone.
W interfejsie API zbudowanym od podstaw za pomocą
Optional
ilekroć zwracana wartość może być pusta, a zwracanie zwykłego obiektu tylko wtedy, gdy nie może byćnull
(konwencja), kod klienta może porzucić sprawdzanie wartości zerowej prostych wartości zwracanych przez prosty obiekt ...Oczywiście
Optional
może być również użyty jako argument metody, być może lepszy sposób wskazywania opcjonalnych argumentów niż 5 lub 10 metod przeciążania w niektórych przypadkach.Optional
oferuje inne wygodne metody, takie jak takie,orElse
które pozwalają na użycie wartości domyślnej iifPresent
działa z wyrażeniami lambda .Zapraszam do lektury tego artykułu (mojego głównego źródła do napisania tej odpowiedzi), w którym
NullPointerException
problematyczne (i ogólnie zerowy wskaźnik), a także (częściowe) rozwiązanie, któreOptional
zostały przez nie wyjaśnione: Java Optional Objects .źródło
if(optional.isPresent()){ optional.get(); }
zamiastoptional.ifPresent(o -> { ...})
W zależności od rodzaju obiektów, które sprawdzasz, możesz użyć niektórych klas w apache commons, takich jak: apache commons lang i apache commons kolekcje
Przykład:
lub (w zależności od tego, co musisz sprawdzić):
Klasa StringUtils jest tylko jedną z wielu; w społecznościach jest całkiem sporo dobrych klas, które wykonują zerową bezpieczną manipulację.
Poniżej znajduje się przykład użycia walidacji zerowej w JAVA po dołączeniu biblioteki apache (commons-lang-2.4.jar)
A jeśli używasz Springa, Spring ma również tę samą funkcjonalność w swoim pakiecie, zobacz bibliotekę (spring-2.4.6.jar)
Przykład użycia tej statycznej klasyf od wiosny (org.springframework.util.Assert)
źródło
Musisz sprawdzić obiekt! = Null tylko, jeśli chcesz obsłużyć przypadek, w którym obiekt może być null ...
Istnieje propozycja dodania nowych adnotacji w Javie 7, aby pomóc z parametrami null / notnull: http://tech.puredanger.com/java7/#jsr308
źródło
Jestem fanem kodu „fail fast”. Zadaj sobie pytanie - czy robisz coś użytecznego w przypadku, gdy parametr ma wartość null? Jeśli nie masz jednoznacznej odpowiedzi na pytanie, co powinien zrobić Twój kod w tym przypadku ... To znaczy, nigdy nie powinno być zerowe, to zignoruj go i zezwól na zgłoszenie wyjątku NullPointerException. Kod wywołujący będzie miał takie samo znaczenie dla NPE, jak dla IllegalArgumentException, ale deweloperowi łatwiej będzie debugować i zrozumieć, co poszło nie tak, jeśli zostanie wygenerowany NPE, niż twój kod próbujący wykonać inną nieoczekiwaną nieprzewidzianą sytuację. logika - która ostatecznie powoduje awarię aplikacji.
źródło
Ramy kolekcji Google to dobry i elegancki sposób na uzyskanie kontroli zerowej.
W klasie biblioteki jest taka metoda:
A użycie jest (z
import static
):Lub w twoim przykładzie:
źródło
getThing().getItsThing().getOtherThing().wowEncapsulationIsBroken().setLol("hi");
Czasami masz metody, które działają na jego parametrach, które definiują operację symetryczną:
Jeśli wiesz, że b nigdy nie może być zerowy, możesz go po prostu zamienić. Jest to najbardziej przydatne dla równych: Zamiast
foo.equals("bar");
lepiej zrobić"bar".equals(foo);
.źródło
equals
(może to być dowolna metoda), że poprawnie obsłuży wartość null. Naprawdę to wszystko polega na przekazaniu odpowiedzialności komuś innemu (lub innej metodzie).equals
(lub jakakolwiek inna metoda) i tak musi to sprawdzićnull
. Lub wyraźnie zaznacz, że tak nie jest.Zamiast Wzorca Null Object - który ma swoje zastosowanie - można rozważyć sytuacje, w których obiekt NULL jest błędem.
Po zgłoszeniu wyjątku sprawdź ślad stosu i przeanalizuj błąd.
źródło
Null nie jest „problemem”. Jest integralną częścią kompletnego zestawu narzędzi do modelowania. Oprogramowanie ma na celu modelowanie złożoności świata, a ciężar zerowy ponosi. Null oznacza „Brak danych” lub „Nieznany” w Javie i tym podobne. Dlatego do tych celów należy używać wartości zerowych. Nie preferuję wzorca „obiekt zerowy”; Myślę, że rodzi to problem „ kto będzie pilnował strażników ”.
Jeśli zapytasz mnie, jak ma na imię moja dziewczyna, powiem ci, że nie mam dziewczyny. W języku Java zwracam null. Alternatywą byłoby rzucenie znaczącego wyjątku, aby wskazać jakiś problem, który nie może być (lub nie „
W przypadku „nieznanego pytania” podaj „nieznaną odpowiedź”. (Bądź zerowy, jeśli jest to poprawne z biznesowego punktu widzenia) Sprawdzanie argumentów dla wartości null raz w metodzie przed użyciem zwalnia wielu dzwoniących od sprawdzania ich przed wywołaniem.
Poprzedni prowadzi do normalnego przepływu logiki, aby nie uzyskać zdjęcia nieistniejącej dziewczyny z mojej biblioteki zdjęć.
I pasuje do nowego nadchodzącego Java API (czekamy)
Chociaż raczej „normalnym przepływem biznesu” jest nie znajdowanie zdjęć przechowywanych w bazie danych dla niektórych osób, w innych przypadkach używałem par takich jak poniżej.
I nie bój się pisać
<alt> + <shift> + <j>
(generuj javadoc w Eclipse) i pisz trzy dodatkowe słowa dla swojego publicznego API. Będzie to więcej niż wystarczające dla wszystkich oprócz tych, którzy nie czytają dokumentacji.lub
Jest to raczej teoretyczny przypadek iw większości przypadków powinieneś preferować java null safe API (w przypadku, gdy zostanie wydany za 10 lat), ale
NullPointerException
jest podklasąException
. Jest to więc formaThrowable
wskazująca warunki, które rozsądna aplikacja może chcieć złapać ( javadoc )! Aby skorzystać z pierwszej największej zalety wyjątków i oddzielić kod obsługi błędów od kodu „zwykłego” ( według twórców Javy ), jak dla mnie, należy łapaćNullPointerException
.Mogą pojawić się pytania:
P: Co się stanie, jeśli
getPhotoDataSource()
zwróci wartość null?A. To zależy od logiki biznesowej. Jeśli nie uda mi się znaleźć albumu ze zdjęciami, nie pokażę ci żadnych zdjęć. Co się stanie, jeśli appContext nie zostanie zainicjowany? Logika biznesowa tej metody jest z tym zgodna. Jeśli ta sama logika powinna być bardziej rygorystyczna niż zgłoszenie wyjątku, jest to część logiki biznesowej i należy zastosować jawne sprawdzenie wartości null (przypadek 3). Te nowe Java Null-safe API lepiej pasuje tu określenie selektywnie, co oznacza i co nie oznacza być inicjowane za fail-szybko w przypadku błędów programisty.
Q. Można wykonać nadmiarowy kod i pobrać niepotrzebne zasoby.
O. Mogłoby to mieć miejsce, gdyby
getPhotoByName()
spróbował otworzyć połączenie z bazą danych, utworzyćPreparedStatement
i użyć nazwiska osoby jako parametru SQL. Podejście do nieznanego pytania daje nieznaną odpowiedź (przypadek 1). Przed pobraniem zasobów metoda powinna sprawdzić parametry i w razie potrzeby zwrócić wynik „nieznany”.P: Podejście to ma negatywny wpływ na wydajność z powodu otwarcia zamknięcia próby.
A. Oprogramowanie powinno być łatwe do zrozumienia i modyfikacji. Dopiero potem można pomyśleć o wydajności i tylko w razie potrzeby! i gdzie potrzeba! ( źródło ) i wiele innych).
PS. Podejście to będzie tak samo rozsądne, jak zastosowanie oddzielnego kodu obsługi błędów od zasady „zwykłego” kodu w niektórych miejscach. Rozważ następny przykład:
PPS. Dla tych, którzy szybko głosują (i nie tak szybko czytają dokumentację), chciałbym powiedzieć, że nigdy w życiu nie złapałem wyjątku zerowej wartości (NPE). Ale ta możliwość została celowo zaprojektowana przez twórców Javy, ponieważ NPE jest podklasą
Exception
. Mamy precedens w historii Java kiedyThreadDeath
toError
nie dlatego, że jest rzeczywiście błąd aplikacji, ale tylko dlatego, że nie miał być złapany! Ile NPE wpisuje się byćError
niżThreadDeath
! Ale to nie jest.Zaznacz „Brak danych” tylko wtedy, gdy wymaga tego logika biznesowa.
i
Jeśli appContext lub dataSource nie zostanie zainicjowany, nieobsługiwane środowisko wykonawcze NullPointerException zabije bieżący wątek i zostanie przetworzone przez Thread.defaultUncaughtExceptionHandler (w celu zdefiniowania i użycia ulubionego programu rejestrującego lub innego mechanizmu powiadomień). Jeśli nie zostanie ustawiony, ThreadGroup # uncaughtException wypisze stos śledzenia do błędu systemowego. Należy monitorować dziennik błędów aplikacji i otwierać problem Jira dla każdego nieobsługiwanego wyjątku, który w rzeczywistości jest błędem aplikacji. Programista powinien naprawić błąd gdzieś podczas inicjalizacji.
źródło
NullPointerException
i powrótnull
jest okropne do debugowania. W końcu i tak otrzymujesz NPE i naprawdę trudno jest ustalić, co było pierwotnie puste.if (maybeNull.hasValue()) {...}
więc jaka jest różnicaif (maybeNull != null)) {...}
?Maybe<T>
lubOptional<T>
nie w przypadku, gdy twójT
może być zerowy, ale w przypadku, gdy nigdy nie powinien być zerowy. Jeśli masz typ, który wyraźnie oznacza, że „ta wartość może być zerowa - używaj z rozwagą”, i konsekwentnie używasz i zwracasz taki typ, to za każdym razem, gdy widzisz zwykły staryT
kod, możesz założyć, że nigdy nie jest on zerowy. (Oczywiście byłoby to o wiele bardziej przydatne, gdyby było możliwe do wyegzekwowania przez kompilator.)Java 7 ma nową
java.util.Objects
klasę narzędzi, w której istniejerequireNonNull()
metoda. Wszystko to powoduje wyrzucenie a,NullPointerException
jeśli jego argument ma wartość NULL, ale trochę czyści kod. Przykład:Ta metoda jest najbardziej przydatna do sprawdzania tuż przed przypisaniem w konstruktorze, gdzie każde jej użycie może zapisać trzy wiersze kodu:
staje się
źródło
doCalc(someObject)
.doCalc()
i nie od razu wyrzuci NPE, gdy otrzyma wartość NULL, musisz sam sprawdzić, czy jest NULL i wyrzucić NPE. Po toObjects.requireNonNull()
jest.Ostatecznie jedynym sposobem na całkowite rozwiązanie tego problemu jest użycie innego języka programowania:
nil
i absolutnie nic się nie wydarzy. To sprawia, że większość kontroli zerowych jest niepotrzebna, ale może znacznie utrudnić diagnozowanie błędów.źródło
Rzeczywiście powszechny „problem” w Javie.
Po pierwsze, moje przemyślenia na ten temat:
Uważam, że źle jest „coś zjeść”, gdy wartość NULL została przekazana, gdy wartość NULL nie jest prawidłową wartością. Jeśli nie wychodzisz z metody z jakimś błędem, oznacza to, że nic nie poszło źle w twojej metodzie, co nie jest prawdą. Wtedy prawdopodobnie zwrócisz null w tym przypadku, a w metodzie odbierającej ponownie sprawdzasz, czy null, i nigdy się nie kończy, i kończysz na „if! = Null” itp.
Tak więc, IMHO, null musi być błędem krytycznym, który uniemożliwia dalsze wykonanie (to znaczy, gdy null nie jest prawidłową wartością).
Sposób rozwiązania tego problemu jest następujący:
Najpierw przestrzegam tej konwencji:
I wreszcie, w kodzie, pierwszy wiersz metody publicznej wygląda następująco:
Zauważ, że addParam () zwraca self, dzięki czemu możesz dodać więcej parametrów do sprawdzenia.
Metoda
validate()
rzuci sprawdzone,ValidationException
jeśli którykolwiek z parametrów ma wartość NULL (zaznaczone lub niezaznaczone jest bardziej problemem projektowym / smakowym, ale mójValidationException
jest zaznaczony).Wiadomość będzie zawierać następujący tekst, jeśli na przykład „plany” są puste:
„ Napotkano niedozwoloną wartość argumentu null dla parametru [plany] ”
Jak widać, druga wartość w metodzie addParam () (ciąg) jest potrzebna dla wiadomości użytkownika, ponieważ nie można łatwo wykryć przekazanej nazwy zmiennej, nawet z odbiciem (zresztą nie jest to temat tego postu ...).
I tak, wiemy, że poza tą linią nie napotkamy już wartości zerowej, więc po prostu bezpiecznie wywołujemy metody na tych obiektach.
W ten sposób kod jest czysty, łatwy w utrzymaniu i czytelny.
źródło
Zadanie tego pytania wskazuje, że możesz być zainteresowany strategiami obsługi błędów. Architekt Twojego zespołu powinien zdecydować, jak naprawić błędy. Można to zrobić na kilka sposobów:
pozwól, aby wyjątki przeszły przez nie - złap je w „głównej pętli” lub w innej procedurze zarządzania.
Na pewno rzuć okiem również na programowanie zorientowane na aspekt - mają fajne sposoby na wstawienie
if( o == null ) handleNull()
do twojego kodu bajtowego.źródło
Oprócz korzystania
assert
możesz użyć następujących opcji:Jest to nieco lepsze niż:
źródło
if (!something) { x(); } else { y(); }
, byłbym skłonny to tak zrefaktoryzowaćif (something) { y(); } else { x(); }
(chociaż można by argumentować, że!= null
jest to bardziej pozytywna opcja ...). Ale co ważniejsze, ważna część kodu nie jest zawinięta wewnątrz{}
s, a dla większości metod masz jeden poziom mniej wcięcia. Nie wiem, czy to było rozumowanie fastcodejava, ale to byłoby moje.Tylko nigdy nie używaj null. Nie pozwól na to.
W moich klasach większość pól i zmiennych lokalnych ma niepuste wartości domyślne i wszędzie w kodzie dodam instrukcje kontraktowe (zawsze włączone), aby upewnić się, że jest ono egzekwowane (ponieważ jest bardziej zwięzłe i bardziej wyraziste niż na to pozwalanie wymyślić jako NPE, a następnie rozwiązać numer linii itp.).
Po przyjęciu tej praktyki zauważyłem, że problemy same się rozwiązały. Łapiesz rzeczy na wcześniejszym etapie procesu projektowania przez przypadek i zdajesz sobie sprawę, że masz słaby punkt ... a co ważniejsze ... pomaga to uwzględnić problemy różnych modułów, różne moduły mogą sobie "ufać" i nie zaśmieca kod z
if = null else
konstrukcjami!Jest to programowanie defensywne i skutkuje znacznie czystszym kodem na dłuższą metę. Zawsze odkażaj dane, np. Tutaj poprzez egzekwowanie sztywnych standardów, a problemy znikną.
Kontrakty są jak testy mini-jednostek, które zawsze trwają, nawet w produkcji, a kiedy coś się nie powiedzie, wiesz dlaczego, a nie losowy NPE, musisz jakoś wymyślić.
źródło
Guava, bardzo przydatna biblioteka podstawowa Google, ma przyjemny i użyteczny interfejs API pozwalający uniknąć wartości zerowych. Uważam, że UsingAndAvoidingNullExplained jest bardzo pomocny.
Jak wyjaśniono w wiki:
Stosowanie:
źródło
Jest to bardzo częsty problem dla każdego programisty Java. Tak więc istnieje oficjalne wsparcie w Javie 8, aby rozwiązać te problemy bez zaśmieconego kodu.
Java 8 została wprowadzona
java.util.Optional<T>
. Jest to pojemnik, który może zawierać lub nie mieć wartości innej niż zero. Java 8 zapewnił bezpieczniejszy sposób obsługi obiektu, którego wartość w niektórych przypadkach może być zerowa. Jest inspirowany pomysłami Haskell i Scali .W skrócie, klasa Optional zawiera metody jawnego radzenia sobie z przypadkami, w których wartość jest obecna lub nieobecna. Jednak przewaga w porównaniu z referencjami zerowymi polega na tym, że Opcjonalna klasa <T> zmusza do myślenia o przypadku, gdy wartość nie jest obecna. W rezultacie możesz zapobiec niezamierzonym wyjątkom wskaźnika zerowego.
W powyższym przykładzie mamy fabrykę usług domowych, która zwraca uchwyt do wielu urządzeń dostępnych w domu. Ale te usługi mogą, ale nie muszą być dostępne / funkcjonalne; oznacza to, że może to spowodować wyjątek NullPointerException. Zamiast dodawać null
if
warunek przed użyciem jakiejkolwiek usługi, zawińmy go w Opcjonalne <Service>.OWIJANIE DO OPCJI <T>
Rozważmy metodę uzyskania referencji usługi z fabryki. Zamiast zwracać odwołanie do usługi, zawiń je Opcjonalnie. Informuje użytkownika interfejsu API, że zwrócona usługa może, ale nie musi być dostępna / funkcjonalna, używać defensywnie
Jak widać,
Optional.ofNullable()
zapewnia łatwy sposób na zapakowanie referencji. Istnieją inne sposoby uzyskania odniesienia do OpcjonalnegoOptional.empty()
:Optional.of()
. Jeden do zwrócenia pustego obiektu zamiast przestrajania wartości null, a drugi do zawinięcia odpowiednio obiektu, który nie ma wartości zerowej.W JAKI SPOSÓB DOKŁADNIE POMAGA UNIKAĆ KONTROLI NULL?
Po zawinięciu obiektu referencyjnego, Opcjonalne udostępnia wiele przydatnych metod do wywoływania metod na opakowanym odwołaniu bez NPE.
Optional.ifPresent wywołuje danego konsumenta z referencją, jeśli jest to wartość inna niż null. W przeciwnym razie nic nie robi.
Reprezentuje operację, która akceptuje pojedynczy argument wejściowy i nie zwraca żadnego wyniku. W przeciwieństwie do większości innych interfejsów funkcjonalnych, oczekuje się, że Konsument będzie działał poprzez skutki uboczne. Jest tak czysty i łatwy do zrozumienia. W powyższym przykładzie kodu
HomeService.switchOn(Service)
jest wywoływane, jeśli odwołanie Opcjonalne wstrzymanie ma wartość inną niż null.Bardzo często używamy operatora trójskładnikowego do sprawdzania stanu zerowego i zwracamy wartość alternatywną lub domyślną. Opcjonalny zapewnia inny sposób obsługi tego samego warunku bez sprawdzania wartości NULL. Optional.orElse (defaultObj) zwraca defaultObj, jeśli opcja ma wartość pustą. Użyjmy tego w naszym przykładowym kodzie:
Teraz HomeServices.get () robi to samo, ale w lepszy sposób. Sprawdza, czy usługa jest już zainicjowana. Jeśli tak, zwróć to samo lub utwórz nową nową usługę. Opcjonalne <T>. Lub Else (T) pomaga zwrócić wartość domyślną.
Wreszcie, oto nasz NPE oraz zerowy kod bez czeku:
Cały post to NPE i kod zerowy Null… Naprawdę? .
źródło
if(homeServices != null) {
który można zmienić nahomeServices.ifPresent(h -> //action)
;Lubię artykuły z Nat Pryce. Oto linki:
W artykułach znajduje się również link do repozytorium Git dla typu Java Może typu, który uważam za interesujący, ale nie sądzę, aby sam mógł zmniejszyć wzdęcia kodu sprawdzającego. Po przeprowadzeniu pewnych badań w Internecie, myślę, że ! = Wzdęcia z zerowym kodem można zmniejszyć głównie przez staranne zaprojektowanie.
źródło
Próbowałem,
NullObjectPattern
ale dla mnie nie zawsze jest to najlepsza droga. Czasami „brak działania” jest niewłaściwy.NullPointerException
jest wyjątkiem Runtime, co oznacza, że jest to wina programistów i przy wystarczającym doświadczeniu informuje dokładnie, gdzie jest błąd.Teraz do odpowiedzi:
Postaraj się, aby wszystkie twoje atrybuty i ich akcesory były jak najbardziej prywatne lub unikaj ich w ogóle ujawniania klientom. Oczywiście możesz mieć wartości argumentów w konstruktorze, ale zmniejszając zakres, nie pozwalasz klasie klienta przekazać niepoprawnej wartości. Jeśli musisz zmodyfikować wartości, zawsze możesz utworzyć nową
object
. Sprawdzasz wartości w konstruktorze tylko raz, a w pozostałych metodach możesz być prawie pewien, że wartości nie są równe null.Oczywiście doświadczenie jest lepszym sposobem na zrozumienie i zastosowanie tej sugestii.
Bajt!
źródło
Prawdopodobnie najlepszą alternatywą dla Java 8 lub nowszej jest użycie tej
Optional
klasy.Jest to szczególnie przydatne w przypadku długich łańcuchów możliwych wartości zerowych. Przykład:
Przykład, jak zgłosić wyjątek na wartość NULL:
Java 7 wprowadziła
Objects.requireNonNull
metodę, która może się przydać, gdy należy sprawdzić coś pod kątem braku wartości. Przykład:źródło
Czy mogę udzielić bardziej ogólnej odpowiedzi!
My zwykle zmierzyć się z tym problem, gdy metody uzyskać parametry w taki sposób, że nie oczekiwano (metoda złe połączenie jest winą programisty). Na przykład: spodziewasz się uzyskać obiekt, zamiast tego otrzymujesz zero. Oczekujesz, że otrzymasz Ciąg z co najmniej jednym znakiem, zamiast tego otrzymasz Pusty Ciąg ...
Więc nie ma różnicy między:
}
lub
Oboje chcą upewnić się, że otrzymaliśmy prawidłowe parametry, zanim wykonamy inne funkcje.
Jak wspomniano w niektórych innych odpowiedziach, aby uniknąć powyższych problemów, można postępować zgodnie z wzorcem Projektowanie według umowy . Proszę zobaczyć http://en.wikipedia.org/wiki/Design_by_contract .
Aby zaimplementować ten wzorzec w java, możesz użyć podstawowych adnotacji java, takich jak javax.annotation.NotNull lub użyć bardziej wyrafinowanych bibliotek, takich jak Hibernate Validator .
Tylko próbka:
Teraz możesz bezpiecznie opracować podstawową funkcję swojej metody bez konieczności sprawdzania parametrów wejściowych, chronią one twoje metody przed nieoczekiwanymi parametrami.
Możesz pójść o krok dalej i upewnić się, że w aplikacji można utworzyć tylko poprawne pojęcia. (próbka ze strony walidatora hibernacji)
źródło
javax
z definicji nie jest „rdzeniem Java”.Bardzo lekceważę odpowiedzi sugerujące użycie zerowych obiektów w każdej sytuacji. Ten wzorzec może zerwać kontrakt i pogłębiać problemy coraz głębiej zamiast je rozwiązywać, nie wspominając, że niewłaściwe użycie spowoduje utworzenie kolejnego stosu kodu płyty, który będzie wymagał przyszłej konserwacji.
W rzeczywistości, jeśli coś zwróconego z metody może być zerowe i kod wywołujący musi podjąć decyzję w tej sprawie, powinno być wcześniejsze wywołanie zapewniające stan.
Należy również pamiętać, że wzorzec zerowy obiektów będzie wymagał pamięci, jeśli zostanie użyty bez opieki. W tym celu - instancja obiektu NullObject powinna być współużytkowana między właścicielami, a nie dla każdej z nich stanowić instancję typu unigue.
Nie zalecałbym również używania tego wzorca, w którym typ ma być pierwotną reprezentacją typu - jak jednostki matematyczne, które nie są skalarami: wektory, macierze, liczby zespolone i obiekty POD (Plain Old Data), które mają utrzymywać stan w postaci wbudowanych typów Java. W tym drugim przypadku wywołanie metod gettera zakończy się arbitralnie. Na przykład, co powinna zwrócić metoda NullPerson.getName ()?
Warto rozważyć takie przypadki, aby uniknąć absurdalnych wyników.
źródło
Robiąc to we własnym kodzie, możesz uniknąć! = Kontrola zerowa.
Przez większość czasu kontrole zerowe wydają się chronić pętle nad kolekcjami lub tablicami, więc po prostu zainicjuj je puste, nie będziesz potrzebować żadnych kontroli zerowych.
Jest w tym niewielki narzut, ale warto dla czystszego kodu i mniej NullPointerExceptions.
źródło
Jest to najczęstszy błąd występujący u większości programistów.
Mamy na to wiele sposobów.
Podejście 1:
notNull (Object object, komunikat String)
Podejście 2:
Podejście 3:
Podejście 4:
źródło
źródło
ObjectUtils.defaultIfNull()
. Jest jeszcze jedna ogólna:ObjectUtils.firstNonNull()
, które mogą być wykorzystane do realizacji poniżającego strategii:firstNonNull(bestChoice, secondBest, thirdBest, fallBack);