oggetto == null o null == oggetto?


96

Ho sentito da qualcuno che null == objectè meglio che object == null controllare

per esempio :

void m1(Object obj ) {
   if(null == obj)  // Is this better than object == null ? Why ?
       return ;
   // Else blah blah
}

Ci sono ragioni o questo è un altro mito? Grazie per l'aiuto.


Dupe di 271561 e 1957836 (eccetto per il fatto che questo dice "in Java")
Gishu

20
Java è diverso da C #
Jijoy

5
Se ci fosse un vantaggio significativo in termini di prestazioni, sicuramente il compilatore lo ottimizzerebbe ...
Andreas Dolk

Per i nullriferimenti, la linea d'azione predefinita dovrebbe essere quella di lanciare un NPE. Alcune belle librerie (come la libreria Java JDK7) hanno un metodo qualcosa di simile public static <T> T notNull(T obj) { if (obj == null) { throw new NullPointerException(); } else { return obj; } }. C'è anche @NonNull(o @Nonnull?), Ma viene "cancellato".
Tom Hawtin - tackline

Risposte:


140

Questa è probabilmente un'abitudine appresa da C, per evitare questo tipo di errore di battitura (singolo =anziché doppio ==):

if (object = null) {

La convenzione di mettere la costante sul lato sinistro di ==non è molto utile in Java poiché Java richiede che l'espressione in un ifrestituisca un booleanvalore, quindi a meno che la costante non sia a boolean, si otterrebbe un errore di compilazione in entrambi i modi in cui si inserisce il argomenti. (e se è un booleano, non dovresti usare ==comunque ...)


4
che non è un'abitudine molto utile per java, poiché l'errore di battitura comporterebbe un errore di compilazione su java
radai


3
@Chandru per un booleano, puoi usare x.booleanValue()o !x.booleanValue(). x == trueo x == falsein una condizione l'espressione è un cattivo odore, IMHO.
Laurence Gonsalves

2
Sta verificando la presenza di null qui. E ci sono casi in cui deve davvero controllare un booleano per null poiché null non è né vero né falso.
Chandra Sekar

1
Abituarsi all'uso null == objectsolo per assicurarsi di non sovrascrivere accidentalmente un oggetto con un errore di battitura non dovrebbe essere affatto un caso d'uso. Il che significa che ci stiamo allenando che ora che uso prima "null", va bene, anche se faccio un errore. Ciò non significa che il codice funzioni come previsto. Anche se null = objectviene fornito al posto di null == object, il programma non funzionerà come previsto! Allora non ha senso seguire questa convenzione!
VanagaS

32

Come altri hanno già detto, è un'abitudine appresa da C evitare errori di battitura, sebbene anche in C mi aspetterei compilatori decenti con livelli di avviso sufficientemente alti da fornire un avviso. Come dice Chandru, il confronto con null in Java in questo modo causerebbe problemi solo se si stesse utilizzando una variabile di tipo Boolean(che non si trova nel codice di esempio). Direi che è una situazione piuttosto rara e per cui non vale la pena cambiare il modo in cui scrivi il codice ovunque. (Non mi preoccuperei di invertire gli operandi anche in questo caso; se sto pensando abbastanza chiaramente da considerare di invertirli, sono sicuro di poter contare i segni di uguale.)

Ciò che non è stato menzionato è che molte persone (me compresa certamente) trovano il if (variable == constant)modulo più leggibile - è un modo più naturale di esprimersi. Questa è una ragione per non copiare ciecamente una convenzione da C. Dovresti sempre mettere in discussione le pratiche (come stai facendo qui :) prima di presumere che ciò che può essere utile in un ambiente sia utile in un altro.


3
Accetto ogni parola che hai detto, specialmente la parte "copia ciecamente una convenzione". Sto leggendo un codice in questo momento e lo stile null = object mi infastidisce così tanto che lo cerco e sono venuto qui. Cosa stava pensando il programmatore?
Adrian M

28

Questo non ha molto valore in Java (1.5+) tranne quando il tipo di oggetto è Boolean. In tal caso, questo può ancora essere utile.

if (object = null)non causerà errori di compilazione in Java 1.5+ se l'oggetto è Booleanma lancerà un errore in NullPointerExceptionfase di esecuzione.


Probabilmente intendevi che avrebbe causato un errore di compilazione :)
vava

7
No, non causerà un errore di compilazione quando l'oggetto è booleano.
Chandra Sekar

Non è lo stesso per ogni tipo di oggetto oltre a Boolean?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

2
Per i tipi non booleani, il codice non verrà compilato perché il tipo dell'espressione "object = null" non sarà booleano. A causa dell'auto-boxing, verrà compilato per Boolean.
Chandra Sekar

Ma perché questo comportamento per Boolean? Qualche motivo?
Rohit Banga

9

In Java non c'è una buona ragione.

Un paio di altre risposte hanno affermato che è perché puoi accidentalmente assegnarlo invece di uguaglianza. Ma in Java, devi avere un booleano in un if, quindi questo:

if (o = null)

non verrà compilato.

L'unica volta che questo potrebbe avere importanza in Java è se la variabile è booleana:

int m1(boolean x)
{
    if (x = true)  // oops, assignment instead of equality

4
Ma perché mai scrivere == trueo ugualmente == true == true.
Tom Hawtin - tackline

7
Non c'è un buon motivo per scrivere == true. Ma ho visto così tanto codice pessimo nella mia carriera che non chiedo più perché qualcuno dovrebbe scrivere qualcosa e accetto semplicemente che alcune persone abbiano scritto codice non necessario / discutibile.
R Samuel Klatchko

1
In effetti, c'è un sacco di codice scadente che vola in giro, tuttavia, se considerato x == truecome cattivo perché potrebbe essere scritto erroneamente x = true, non avrebbe molto senso cambiarlo in true == xanziché solo x.
Holger

9

Questo è anche strettamente correlato a:

if ("foo".equals(bar)) {

il che è conveniente se non vuoi occuparti delle NPE:

if (bar!=null && bar.equals("foo")) {

può essere conveniente ma può essere pericoloso blue-walrus.com/2010/11/…
Oliver Watkins

@OliverWatkins: trovo questo articolo debole. Supponiamo che la variabile fosse di tipo int. Se non inizializzato, il valore sarebbe 0 e la promessa dell'articolo non sarebbe valida. Il fatto che le stringhe siano oggetti e gli int siano primitivi è irrilevante per il fatto che un programmatore possa dimenticare di inizializzare una variabile. In questa domanda risolviamo semplicemente la cosa del confronto di stringhe null.
cherouvim

@cherouvim il fatto che intsia un tipo primitivo è rilevante, poiché è impossibile invocare equalssu un int, quindi, non ha senso discutere se usare x.equals(constant)o constant.equals(x)per intvalori. E per i Integervalori, il valore predefinito è nullinvece di 0.
Holger

5

Questo trucco dovrebbe prevenire il v = nulltipo di errori di battitura.

Ma Java consente solo espressioni booleane come if()condizioni, quindi quel trucco non ha molto senso, il compilatore troverà comunque quegli errori di battitura.

Tuttavia, è ancora un trucco prezioso per il codice C / C ++.


3

Per lo stesso motivo lo fai in C; assegnazione è un'espressione, quindi metti il ​​letterale a sinistra in modo da non poterlo sovrascrivere se usi accidentalmente al =posto di ==.


È solo un problema in Java per i tipi booleani, giusto? Qualsiasi altro tipo di assegnazione non avrà un tipo booleano e dovrebbe causare un errore del compilatore.
Scott Smith

1
no, il compilatore Java rileverà quel tipo di errore di battitura qualunque sia l'ordine che preferisci
vava

@Jijoy - Non credo che questo abbia nulla a che fare con le prestazioni. Suona come un vecchio trucco in C per evitare il temuto errore di assegnazione all'interno di un'espressione condizionale. L'idea era che se stai cercando di verificare se è xuguale 5, quando digiti per errore if (x = 5), verrà compilato in modo silenzioso (e restituirà sempre true, indipendentemente dal valore di x). Tuttavia, se prendi l'abitudine di specificare sempre prima il letterale: 'if (5 = x)', il compilatore può ricontrollare il tuo lavoro e farti risparmiare tempo nel debugger. I compilatori moderni rendono superflua questa abitudine.
Scott Smith

6
-1: se usi accidentalmente = non verrà compilato in Java; quindi il motivo di C non si applica.
Jon Skeet

Tecnicamente se objfosse di tipo java.lang.Boolean(B grande), allora potrebbe fare la differenza (penso, non effettivamente provato o altro).
Tom Hawtin - tackline

3

Questo è per le persone che preferiscono avere la costante sul lato sinistro. Nella maggior parte dei casi, avere la costante sul lato sinistro impedirà la generazione di NullPointerException (o di avere un altro nullcheck). Ad esempio, il metodo String equals esegue anche un controllo null. Avere la costante a sinistra ti impedirà di scrivere l'assegno aggiuntivo. Che, in un altro modo, viene eseguito anche in seguito. Avere il valore nullo a sinistra significa semplicemente essere coerenti.

piace:

 String b = null;
 "constant".equals(b);  // result to false
 b.equals("constant");  // NullPointerException
 b != null && b.equals("constant");  // result to false

questo nascondere l'NPE crea solo ancora più difficile trovare bug più a valle
Oliver Watkins,

2

È la condizione di Yoda che scrive in modo diverso

In java

String myString = null;
if (myString.equals("foobar")) { /* ... */ } //Will give u null pointer

yoda condizione

String myString = null;
if ("foobar".equals(myString)) { /* ... */ } // will be false 

1

Confronta con il codice seguente:

    String pingResult = "asd";
    long s = System.nanoTime ( );
    if ( null != pingResult )
    {
        System.out.println ( "null != pingResult" );
    }
    long e = System.nanoTime ( );
    System.out.println ( e - s );

    long s1 = System.nanoTime ( );
    if ( pingResult != null )
    {
        System.out.println ( "pingResult != null" );
    }
    long e1 = System.nanoTime ( );
    System.out.println ( e1 - s1 );

Output (dopo più esecuzioni):

null != pingResult
325737
pingResult != null
47027

Pertanto, pingResult != nullè il vincitore.


7
Esegui il test in un ciclo aggiuntivo! O semplicemente cambia le istruzioni IF. Per farla breve: non c'è differenza! Il primo ciclo è sempre più lento.
Marcel Jaeschke

In questo test, pingResult è sempre non nullo. Cosa succede al momento in cui pingResult è nullo? Scommetto che è indipendente dalla piattaforma, ma sul mio stack Oracle Java 1.6 / Linux, i risultati sono praticamente uniformi (in un ciclo), tranne se pingResult è nullo, entrambi i controlli sono più veloci di qualche percento.
Salmo dell'orco33

1
se metti "pingResult! = null block prima di null! = pingResult block, risulterà qualcosa come" pingResult! = null 325737 "
Sola Yang

Come dice @Sola Yang, se metti pingResult! = Null prima, vedrai che ci vuole più tempo di null! = PingResult. Se pingResult! = Null era più veloce di null! = PingResult l'IDE (come IntelliG, Eclipse, ...) farà un avvertimento per costringere gli sviluppatori a utilizzare questo ruolo;)
adil.hilmi

1

A causa della sua proprietà commutativa , l'unica differenza tra object == nulle null == object(la versione Yoda ) è di natura cognitiva : come il codice viene letto e digerito dal lettore. Non conosco la risposta definitiva, ma so che personalmente preferisco confrontare l'oggetto che sto ispezionando con qualcos'altro, piuttosto che confrontare qualcos'altro con l'oggetto che sto ispezionando , se ha senso. Inizia con il soggetto, quindi il valore con cui confrontarlo.

In alcune altre lingue questo stile di confronto è più utile.

Per difendersi dal segno "=" mancante in generale, però, penso che scrivere null == objectsia un atto di programmazione difensiva fuorviante . Il modo migliore per aggirare questo particolare codice è garantire il comportamento con un test junit. Ricorda, il possibile errore di perdere un "=" non dipende dagli argomenti di input del metodo - non sei dipendente dall'uso corretto di questa API da parte di altre persone - quindi un test junit è perfetto per proteggersi da quello. Comunque vorrai scrivere dei test junit per verificare il comportamento; un "=" mancante rientra naturalmente nell'ambito.

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.