&& (AND) e || (OR) nelle dichiarazioni IF


137

Ho il codice seguente:

if(!partialHits.get(req_nr).containsKey(z) || partialHits.get(req_nr).get(z) < tmpmap.get(z)){  
    partialHits.get(z).put(z, tmpmap.get(z));  
}

dove si partialHitstrova una mappa hash.
Cosa succederà se la prima affermazione è vera? Java continuerà a controllare la seconda istruzione? Perché per rendere vera la prima affermazione, HashMap non dovrebbe contenere la chiave fornita, quindi se la seconda affermazione è selezionata, otterrò NullPointerException.
Quindi, in parole semplici, se abbiamo il seguente codice

if(a && b)  
if(a || b)

Java controlla bse aè falso nel primo caso e se aè vero nel secondo caso?

Risposte:


202

No, non verrà valutato. E questo è molto utile. Ad esempio, se è necessario verificare se una stringa non è nulla o vuota, è possibile scrivere:

if (str != null && !str.isEmpty()) {
  doSomethingWith(str.charAt(0));
}

o viceversa

if (str == null || str.isEmpty()) {
  complainAboutUnusableString();
} else {
  doSomethingWith(str.charAt(0));
}

Se non avessimo "cortocircuiti" in Java, riceveremmo molte NullPointerExceptions nelle righe di codice sopra riportate.


Esistono confronti bit per bit in modo da poter valutare entrambe le espressioni? cioè se (str! = null | str.isEmpty ())? (ovviamente questo non è un esempio pratico, in realtà è stupido, ma hai avuto l'idea)
Kezzer,

5
Finché le espressioni non hanno effetti collaterali, la semantica di corto circuito è logicamente equivalente alla valutazione completa. Cioè, se A è vero, sai che A || B è vero senza dover valutare B. L'unica volta che farà la differenza è se un'espressione ha effetti collaterali. Come per gli altri operatori, puoi usare *e +come logico ande or; ((A?1:0) * (B?1:0)) == 1, ((A?1:0) + (B?1:0)) > 0. Si può anche fare xor: ((A?1:0) + (B?1:0)) == 1.
uscita il

1
@Kezzer: è davvero un confronto bit a bit? Penso che sia un booleanoperatore (logico). È diverso bitwisedall'operatore (intero), nonostante abbia lo stesso simbolo ...
user85421

4
Un trucco utile quando si desidera alternare tra '&&' e '||' espressioni è di negare l'intera espressione, in modo che: !(str != null && !str.isEmpty()) diventi: (str !(!=) null !(&&) !(!)str.isEmpty()) e poi: (str == null || str.isEmpty()) perché: !(!=) is == !(&&) is || !(!) eliminates itself altre negazioni utili sono: !(<) is >= !(>) is <= e viceversa
egallardo

68

Java ha 5 diversi operatori di confronto booleano: &, &&, |, ||, ^

& e && sono operatori "e", | e || "o" operatori, ^ è "xor"

I singoli controlleranno ogni parametro, indipendentemente dai valori, prima di verificare i valori dei parametri. I doppi controlleranno prima il parametro sinistro e il suo valore e se true( ||) o false( &&) lasceranno intatto il secondo. Suono compilato? Un semplice esempio dovrebbe chiarire:

Dato per tutti gli esempi:

 String aString = null;

E:

 if (aString != null & aString.equals("lala"))

Entrambi i parametri vengono controllati prima che venga eseguita la valutazione e verrà generata una NullPointerException per il secondo parametro.

 if (aString != null && aString.equals("lala"))

Il primo parametro viene controllato e viene restituito false, quindi il secondo parametro non verrà controllato, poiché il risultato è falsecomunque.

Lo stesso per OR:

 if (aString == null | !aString.equals("lala"))

Aumenterà anche NullPointerException.

 if (aString == null || !aString.equals("lala"))

Il primo parametro viene controllato e viene restituito true, quindi il secondo parametro non verrà controllato, poiché il risultato è truecomunque.

XOR non può essere ottimizzato, perché dipende da entrambi i parametri.


3
"Java ha 4 diversi operatori di confronto booleano: &, &&, |, ||" ... Stai dimenticando ^(xor).
aioobe,

Oh, non sapevo che controlla anche i valori booleani booleani. Finora l'ho usato solo per maschere di bit.
Hardcoded


20

Tutte le risposte qui sono ottime ma, solo per illustrare da dove proviene, per domande come questa è bene andare alla fonte: la specifica del linguaggio Java.

La sezione 15:23, Operatore condizionale e (&&) , dice:

L'operatore && è simile a & (§15.22.2), ma valuta il suo operando di destra solo se il valore dell'operando di sinistra è vero. [...] In fase di esecuzione, l'espressione dell'operando di sinistra viene valutata per prima [...] se il valore risultante è falso, il valore dell'espressione condizionale ed è falso e l'espressione dell'operando di destra non viene valutata . Se il valore dell'operando di sinistra è vero, l'espressione di destra viene valutata [...] il valore risultante diventa il valore dell'espressione-condizionale. Pertanto, && calcola lo stesso risultato di & su operandi booleani. Differisce solo dal fatto che l'espressione dell'operando di destra viene valutata in modo condizionale piuttosto che sempre.

E allo stesso modo, Sezione 15:24, Operatore condizionale-o (||) , dice:

Il || operatore è come | (§15.22.2), ma valuta il suo operando di destra solo se il valore dell'operando di sinistra è falso. [...] In fase di esecuzione, l'espressione dell'operando di sinistra viene valutata per prima; [...] se il valore risultante è vero, il valore dell'espressione condizionale o è vero e l'espressione dell'operando di destra non viene valutata. Se il valore dell'operando di sinistra è falso, viene valutata l'espressione di destra; [...] il valore risultante diventa il valore del condizionale o dell'espressione. Pertanto, || calcola lo stesso risultato di | su operandi booleani o booleani. Differisce solo dal fatto che l'espressione dell'operando della mano destra viene valutata in modo condizionale piuttosto che sempre.

Un po 'ripetitivo, forse, ma la migliore conferma di come funzionano esattamente. Allo stesso modo l'operatore condizionale (? :) valuta solo la "metà" appropriata (metà sinistra se il valore è vero, metà destra se è falso), consentendo l'uso di espressioni come:

int x = (y == null) ? 0 : y.getFoo();

senza una NullPointerException.


6

No, se a è vero (in un ortest), b non verrà testato, poiché il risultato del test sarà sempre vero, qualunque sia il valore dell'espressione b.

Fai un semplice test:

if (true || ((String) null).equals("foobar")) {
    ...
}

sarà non gettare una NullPointerException!


6

Corto circuito qui significa che la seconda condizione non verrà valutata.

Se (A & B) si tradurrà in corto circuito se A è falso.

Se (A e B) non si tradurrà in corto circuito se A è Vero.

Se (A || B) provocherà un corto circuito se A è True.

Se (A || B) non provocherà un corto circuito se A è Falso.


4

No, Java non eseguirà il cortocircuito e smetterà di valutare una volta che conosce il risultato.


4

Sì, la valutazione del corto circuito per le espressioni booleane è il comportamento predefinito in tutta la famiglia di tipo C.

Un fatto interessante è che Java utilizza anche la &e |come operandi logici (che sono sovraccarichi, con inti tipi sono le operazioni bit per bit attesi) per valutare tutti i termini dell'espressione, che è anche utile quando è necessario gli effetti collaterali.


Questo è interessante da ricordare: ad esempio dato un metodo changeData (data) che restituisce un valore booleano, quindi: if (a.changeData (data) || b.changeData (data)) {doSomething (); } non esegue changeData su b se a.changeData () restituisce true, ma if (a.changeData (data) | b.changeData (data)) {doSomething ()} esegue changeData () su aeb, anche se quello invocato su un restituito vero.
Sampisa,

0

Questo risale alla differenza di base tra & e &&, | e ||

A proposito, esegui le stesse attività più volte. Non sono sicuro se l'efficienza sia un problema. È possibile rimuovere parte della duplicazione.

Z z2 = partialHits.get(req_nr).get(z); // assuming a value cannout be null.
Z z3 = tmpmap.get(z); // assuming z3 cannot be null.
if(z2 == null || z2 < z3){   
    partialHits.get(z).put(z, z3);   
} 
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.