Java: come verificare se l'oggetto è nullo?


89

Sto creando un'applicazione che recupera immagini dal web. Nel caso in cui l'immagine non possa essere recuperata, è necessario utilizzare un'altra immagine locale.

Durante il tentativo di eseguire le seguenti righe:

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

La riga if (drawable.equals (null)) genera un'eccezione se drawable è null.

Qualcuno sa come deve essere controllato il valore di drawable per non generare un'eccezione nel caso in cui sia null e recuperare l'immagine locale (execute drawable = getRandomDrawable ())?


23
Usa if (drawable == null) La chiamata di qualsiasi metodo su un oggetto NULL è una NullPointerException.
diciu

3
Perché non scrivi una solita risposta invece di un commento, diciu?
demone

@JaredBurrows Non modificare il codice in una domanda in un modo che vanifica lo scopo della domanda!
Gilles "SO- smettila di essere malvagio"

@ Gilles Leggi il mio commento editoriale, ho reso il codice più leggibile.
Jared Burrows

@JaredBurrows No, la tua modifica non è stata una modifica di "formattazione". Hai cambiato il codice non funzionante che era l'oggetto della domanda, in codice funzionante che rendeva la domanda discutibile.
Gilles "SO- smettila di essere malvagio"

Risposte:


35

Soluzione Java 8 modificata:

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

Puoi dichiarare drawable final in questo caso.

Come ha sottolineato Chasmo, Android non supporta Java 8 al momento. Quindi questa soluzione è possibile solo in altri contesti.


7
Probabilmente non è una buona idea: torni a Fortran 60 dove vengono valutati entrambi i lati del condizionale, quindi solo uno viene utilizzato. Questo è negativo se il ramo inutilizzato ha dei calcoli, il che è vero quasi sempre, quindi non è un metodo generalmente utile. Sposterei la condizione nella Commonclasse e ti consentirei di fornire un URL di riserva e tenere insieme le responsabilità.
Pete Kirkham

1
L'esempio è ora completamente riscritto in Java 8, quindi la mia soluzione non soffre più di valutazioni inutili (come ha sottolineato @PeteKirkham nella mia soluzione originale).
deamon

1
Android non supporta Java 8. Supporta solo fino a Java 7 (se hai kitkat) e ancora non ha invokedynamic, solo la nuova sintassi sugar. Inoltre, Optional.ofimplica che il valore non è nullo e quindi orElseGetnon è necessario. Dovresti usare Optional.ofNullablein questo caso.
Martin Seeler

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

Il equals()metodo verifica l' uguaglianza dei valori , il che significa che confronta il contenuto di due oggetti. Poiché nullnon è un oggetto, si blocca quando si tenta di confrontare il contenuto del proprio oggetto con il contenuto dinull .

L' ==operatore verifica l' uguaglianza dei riferimenti , il che significa che controlla se i due oggetti sono effettivamente lo stesso oggetto . Ciò non richiede che gli oggetti esistano effettivamente; anche due oggetti inesistenti ( nullriferimenti) sono uguali.


56
Voglio aggiungere un suggerimento molto prezioso: se hai stringhe o costanti da confrontare, inseriscile sempre per prime nella clausola uguale. (if ("coyote" .equals (myDogString))) è molto meglio di (if (myDogString.equals ("coyote"))) perché nel secondo caso myDogString può essere nullo e genera un NPE mentre nel primo caso no non importa se myDogString è null.
Thorsten S.

21
Conosciuta come una condizione di Yoda: "se un coyote, il cane è ..."
Thomas

1
Vorrei anche aggiungere che poiché Java 7 esiste un metodo Objects.equals (), che non ti interessa della sintassi di Yoda
maryokhin

22

Uso questo approccio:

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

In questo modo trovo che migliora la leggibilità della riga - mentre leggo rapidamente un file sorgente posso vedere che è un controllo nullo.

Riguardo al motivo per cui non puoi chiamare .equals()un oggetto che potrebbe essere null; se il riferimento all'oggetto che hai (cioè 'drawable') è in effetti null, non punta a un oggetto nell'heap. Ciò significa che non c'è alcun oggetto sull'heap su cui la chiamata aequals() può avere esito positivo.

Buona fortuna!


4
Anch'io preferisco il costrutto if (<constant> == <variable>) come un modo per proteggermi da assegnazioni accidentali.
Scott

7

Fai da te

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

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

6
drawable.equals(null)

La riga precedente chiama il metodo "equals (...)" sull'oggetto disegnabile.

Quindi, quando drawable non è nullo ed è un oggetto reale, allora tutto va bene poiché chiamare il metodo "equals (null)" restituirà "false"

Ma quando "drawable" è null, significa chiamare il metodo "equals (...)" su un oggetto null, significa chiamare un metodo su un oggetto che non esiste, quindi genera "NullPointerException"

Per verificare se un oggetto esiste e non è nullo, utilizzare quanto segue

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

Nella condizione precedente, stiamo verificando che la variabile di riferimento "drawable" sia nulla o contenga un valore (riferimento al suo oggetto) in modo che non genererà eccezioni nel caso in cui drawable sia nullo come controllo

null == null

è valido.


5

if (yourObject instanceof yourClassName)valuterà falsese yourObjectè null.


0

Probabilmente è leggermente più efficiente catturare una NullPointerException. I metodi precedenti indicano che il runtime verifica due volte la presenza di puntatori nulli.


1
Dov'è la if x == nullsoluzione del doppio check in ?
demone

Dopo l'istruzione if, il runtime verificherà nuovamente la presenza di un puntatore nullo quando viene utilizzato l'oggetto. Non so se sia ottimizzato o meno dal compilatore, però.
Tom R

4
Questo va contro la saggezza convenzionale, utilizzando le eccezioni come flusso di controllo.
James

1
Le eccezioni sono molto costose, poiché devono creare un intero stacktrace.
demone

0

Usa google guava libs per gestire is-null-check (aggiornamento del demone)

Drawable drawable = Optional.of(Common.getDrawableFromUrl(this, product.getMapPath())).or(getRandomDrawable());

Meglio usare Java 8 Optionaloggi.
demone

-1

Solo per dare qualche idea allo sviluppatore di sorgenti Java Oracle :-)

La soluzione esiste già in .Net ed è molto più leggibile!

In Visual Basic .Net

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

In C #

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

Queste soluzioni sono potenti come soluzioni Java opzionali (la stringa predefinita viene valutata solo se il valore originale è nullo) senza utilizzare l'espressione lambda, solo aggiungendo un nuovo operatore.

Solo per vedere rapidamente la differenza con la soluzione Java, ho aggiunto le 2 soluzioni Java

Utilizzo di Opzionale in Java

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

Utilizzo di {} in Java

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

Personalmente mi piace VB.Net ma preferisco ?? C#o if {}soluzione in Java ... e tu?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.