Java: Jak sprawdzić, czy obiekt jest pusty?

89

Tworzę aplikację, która pobiera obrazy z sieci. W przypadku, gdy nie można pobrać obrazu, należy użyć innego obrazu lokalnego.

Podczas próby wykonania następujących linii:

Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
if (drawable.equals(null)) {
  drawable = getRandomDrawable();
}

Linia if (drawable.equals (null)) zgłasza wyjątek, jeśli drawable ma wartość null.

Czy ktoś wie, jak należy sprawdzić wartość drawable, aby nie zgłaszać wyjątku w przypadku, gdy jest null i pobrać lokalny obraz (wykonaj drawable = getRandomDrawable ())?

Niko Gamulin
źródło
23
Użyj if (drawable == null) Wywołanie dowolnej metody na obiekcie NULL jest wyjątkiem NullPointerException.
diciu
3
Dlaczego nie napiszesz zwykłej odpowiedzi zamiast komentarza, diciu?
demon
@JaredBurrows Nie edytuj kodu w pytaniu w sposób, który przeczy celowi pytania!
SO- Gilles 'SO- przestań być zły'
@Gilles Przeczytaj mój komentarz redakcyjny, uczyniłem kod bardziej czytelnym.
Jared Burrows,
@JaredBurrows Nie, Twoja edycja nie była zmianą „formatowania”. Zmieniłeś niedziałający kod, który był przedmiotem pytania, na działający kod, który sprawił, że pytanie było dyskusyjne.
SO- Gilles 'SO- przestań być zły'

Odpowiedzi:

35

Edytowane rozwiązanie Java 8:

final Drawable drawable = 
    Optional.ofNullable(Common.getDrawableFromUrl(this, product.getMapPath()))
        .orElseGet(() -> getRandomDrawable());

Możesz zadeklarować drawable finalw tym przypadku.

Jak zauważył Chasmo, Android nie obsługuje obecnie Java 8. Więc to rozwiązanie jest możliwe tylko w innych kontekstach.

demon
źródło
7
Prawdopodobnie nie jest to dobry pomysł - wracasz do Fortran 60, w którym obie strony warunku są oceniane, a następnie używana jest tylko jedna. Jest to złe, jeśli nieużywana gałąź ma jakieś obliczenia, co jest prawdą przez większość czasu, więc nie jest to ogólnie użyteczna metoda. Przeniósłbym warunek do Commonklasy i pozwoliłbym ci podać zastępczy adres URL i zachować razem obowiązki.
Pete Kirkham,
1
Przykład jest teraz całkowicie przepisany w Javie 8, więc moje rozwiązanie nie cierpi już z powodu bezużytecznych ocen (jak @PeteKirkham wskazał w moim oryginalnym rozwiązaniu).
deamon
1
Android nie obsługuje Java 8. Obsługuje tylko do wersji Java 7 (jeśli masz KitKat) i nadal nie ma wywołania dynamicznego, tylko nowy cukier składniowy. Poza tym Optional.ofoznacza, że ​​wartość nie jest zerowa, a zatem orElseGetjest niepotrzebna. Powinieneś użyć Optional.ofNullablew tym przypadku.
Martin Seeler,
181
Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
if (drawable == null) {
    drawable = getRandomDrawable();
}

Te equals()kontrole metoda dla wartości równości, co oznacza, że Porównuje zawartość dwóch obiektów. Ponieważ nullnie jest obiektem, powoduje to awarię podczas próby porównania zawartości obiektu z zawartością null.

Te ==kontrole operatorskie dla odniesienia równości, co oznacza, że to wygląda, czy dwa obiekty są rzeczywiście bardzo sam obiekt . Nie wymaga to rzeczywistego istnienia obiektów; dwa nieistniejące obiekty ( nullodniesienia) są również równe.

Tomasz
źródło
56
Chcę dodać bardzo cenną wskazówkę: jeśli masz ciągi lub stałe do porównania, zawsze umieszczaj je na pierwszym miejscu w klauzuli równości. (if ("coyote" .equals (myDogString))) jest dużo lepsze niż (if (myDogString.equals ("coyote"))), ponieważ w drugim przypadku myDogString może mieć wartość null i wyrzuca NPE, podczas gdy w pierwszym przypadku tak nie jest nie ma znaczenia, jeśli myDogString ma wartość null.
Thorsten S.
21
Znany jako stan Yody: „jeśli kojot, pies jest…”
Thomas
1
Chciałbym również dodać, że od czasu Java 7 istnieje metoda Objects.equals (), która pozwala nie przejmować się składnią Yody
maryokhin
23

Używam tego podejścia:

if (null == drawable) {
  //do stuff
} else {
  //other things
}

W ten sposób uważam, że poprawia czytelność wiersza - kiedy szybko czytam plik źródłowy, widzę, że jest to sprawdzenie zerowe.

W odniesieniu do tego, dlaczego nie możesz wywołać .equals()obiektu, który może być null; jeśli odniesienie do obiektu, które posiadasz (a mianowicie „do rysowania”) jest w rzeczywistości null, nie wskazuje na obiekt na stercie. Oznacza to, że na stercie nie ma obiektu, na którym wywołanie equals()może się powieść.

Powodzenia!

brak kawy
źródło
4
Ja również wolę konstrukcję if (<stała> == <zmienna>) jako sposób ochrony przed przypadkowym przypisaniem.
Scott,
8

majsterkowanie

private boolean isNull(Object obj) {
    return obj == null;
}

Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
if (isNull(drawable)) {
    drawable = getRandomDrawable();
}
Eddie B.
źródło
6
drawable.equals(null)

Powyższy wiersz wywołuje metodę „equals (...)” na obiekcie rysowalnym.

Tak więc, gdy drawable nie ma wartości null i jest rzeczywistym obiektem, wszystko idzie dobrze, ponieważ wywołanie metody „equals (null)” zwróci wartość „false”

Ale kiedy „drawable” jest null, oznacza to wywołanie metody „equals (...)” na obiekcie zerowym, czyli wywołanie metody na obiekcie, który nie istnieje, więc rzuca „NullPointerException”

Aby sprawdzić, czy obiekt istnieje i czy nie jest pusty, użyj następujących poleceń

if(drawable == null) {
    ...
    ...
}

W powyższym warunku sprawdzamy, czy zmienna referencyjna "drawable" jest pusta lub zawiera jakąś wartość (odniesienie do jej obiektu), więc nie zgłosi wyjątku w przypadku, gdy drawable jest null jako sprawdzanie

null == null

jest ważna.

Yatendra Goel
źródło
5

if (yourObject instanceof yourClassName)oceni, falseczy yourObjectjest null.

heapuser
źródło
0

Prawdopodobnie nieco bardziej wydajne jest wychwycenie wyjątku NullPointerException. Powyższe metody oznaczają, że środowisko wykonawcze dwukrotnie sprawdza wskaźniki o wartości null.

Do Pana
źródło
1
Gdzie jest rozwiązanie dla podwójnej odprawy if x == null?
deamon
Po instrukcji if środowisko uruchomieniowe ponownie sprawdzi, czy obiekt jest używany, pod kątem pustego wskaźnika. Nie wiem jednak, czy jest to optymalizowane przez kompilator.
Tom R
4
Jest to sprzeczne z konwencjonalną mądrością, wykorzystującą wyjątki jako przepływ kontroli.
James
1
Wyjątki są bardzo drogie, ponieważ muszą utworzyć cały ślad stosu.
deamon
0

Użyj google guava libs do obsługi sprawdzania is-null-check (aktualizacja demona)

Drawable drawable = Optional.of(Common.getDrawableFromUrl(this, product.getMapPath())).or(getRandomDrawable());
Bala
źródło
Lepiej Optionaljuż dziś korzystaj z Javy 8 .
deamon
-1

Tylko po to, by przekazać kilka pomysłów programistom Oracle Source Java :-)

Rozwiązanie już istnieje w .Net i jest bardziej czytelne!

W Visual Basic .Net

Drawable drawable 
    = If(Common.getDrawableFromUrl(this, product.getMapPath())
        ,getRandomDrawable()
        )

W języku C #

Drawable drawable 
    = Common.getDrawableFromUrl(this, product.getMapPath() 
        ?? getRandomDrawable();

Te rozwiązania są potężne jako opcjonalne rozwiązanie Java (domyślny ciąg jest oceniany tylko wtedy, gdy oryginalna wartość ma wartość null) bez użycia wyrażenia lambda, tylko po dodaniu nowego operatora.

Aby szybko zobaczyć różnicę w porównaniu z rozwiązaniem Java, dodałem 2 rozwiązania Java

Używanie opcjonalnego w Javie

Drawable drawable = 
    Optional.ofNullable(Common.getDrawableFromUrl(this, product.getMapPath()))
        .orElseGet(() -> getRandomDrawable());

Używanie {} w Javie

Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
if (drawable != null)
    {
    drawable = getRandomDrawable();
    }

Osobiście lubię VB.Net, ale wolę ?? C#lub if {}rozwiązanie w Javie ... a ty?

schlebe
źródło