2009-11-25 17 views
101

La mia domanda potrebbe essere molto semplice, ma credo che valga la pena di chiedere. Ho il seguente codice:&& (AND) e || (OR) nelle dichiarazioni IF

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 partialHits è un HashMap. Cosa succederà se la prima affermazione è vera? Java controllerà ancora la seconda affermazione? Perché nell'ordine in cui la prima affermazione è vera, la HashMap non deve contenere la chiave data, quindi se la seconda istruzione è selezionata, otterrò NullPointerException.
Quindi, in parole semplici, se abbiamo il seguente codice

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

controllerei Java b se a è falsa nel primo caso, e se è vero a nel secondo caso?

risposta

158

No, non sarà valutato. E questo è molto utile. Come è necessario verificare, se una stringa non è nullo o vuoto, è 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, avremmo ricevuto molte NullPointerExceptions nelle linee di codice di cui sopra.

+0

Esistono confronti bit a bit, quindi è possibile valutare entrambe le espressioni? cioè if (str! = null | str.isEmpty())? (naturalmente questo non è un esempio pratico, in effetti è stupido, ma l'idea è) – Kezzer

+5

Finché le espressioni non hanno effetti collaterali, la semantica di cortocircuito è logicamente equivalente alla valutazione completa. Cioè, se A è vero, sai 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 logici 'and' e' or'; '((A? 1: 0) * (B? 1: 0)) == 1',' ((A? 1: 0) + (B? 1: 0))> 0'. Puoi anche fare 'xor':' ((A? 1: 0) + (B? 1: 0)) == 1'. – outis

+1

@Kezzer: è davvero un confronto bit a bit? Penso che sia un operatore (logico) 'booleano'. È diverso dall'operatore 'bitwise' (intero), nonostante abbia lo stesso simbolo ... –

27

No, non verrà controllato. Questo comportamento si chiama short-circuit evaluation ed è una funzionalità in molte lingue incluso Java.

+2

@Azimuth: sei il benvenuto. Se non sai qualcosa, il modo migliore per risolvere questo è chiedere. –

5

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

Fare un semplice test:

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

sarà non gettare un NullPointerException!

4

No, non lo farà, Java si interromperà e smetterà di valutare una volta che conosce il risultato.

18

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

Section 15:23, Conditional-And operator (&&), dice:

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

E allo stesso modo, Section 15:24, Conditional-Or operator (||), dice:

Il || l'operatore è come | (§15.22.2), ma valuta il suo operando di destra solo se il valore del suo operando di sinistra è falso. [...] In fase di esecuzione, l'espressione dell'operando di sinistra viene valutata per prima; [...] se il valore risultante è true, 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 dell'espressione condizionale. Quindi, || calcola lo stesso risultato di | su operandi booleani o booleani. Differisce solo nel fatto che l'espressione dell'operando di destra è valutata condizionalmente piuttosto che sempre.

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

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

senza un NullPointerException.

4

Sì, la valutazione di cortocircuito per le espressioni booleane è il comportamento predefinito in tutta la famiglia C-like.

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

+0

Ciò è interessante da ricordare: ad es. dato un metodo changeData (dati) 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 se (a.changeData (dati) | b.changeData (dati)) {doSomething()} esegue changeData() su sia a che b, anche se quello invocato su un valore restituito è true. – Sampisa

51

Java ha 5 diversi operatori booleani confrontare: &, & &, |, ||,^

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

I singoli controlleranno tutti i parametri, indipendentemente dai valori, prima di verificare i valori dei parametri. I doppi controlleranno prima il parametro di sinistra e il suo valore e se true (||) o false (&&) non intaccano il secondo. Suono compilato? Un esempio semplice dovrebbe rendere chiaro:

Dato per tutti gli esempi:

String aString = null; 

E:

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

Entrambi i parametri sono controllati prima della valutazione è fatto e un NullPointerException saranno gettati per il secondo parametro.

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

Il primo parametro è controllato e restituisce false, quindi la seconda paramter non verrà controllato, perché il risultato è comunque false.

Lo stesso per O:

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

alzerà NullPointerException, anche.

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

Il primo parametro è controllato e restituisce true, quindi la seconda paramter non verrà controllato, perché il risultato è comunque true.

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

+2

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

+0

Oh, non ero a conoscenza del fatto che controlli anche i valori booleani booleani. L'ho usato solo per maschere di bit, finora. – Hardcoded

0

Torna alla differenza di base tra & e & &, | e ||

BTW si eseguono le stesse operazioni molte volte. Non sono sicuro che l'efficienza sia un problema. Potresti 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); 
} 
4

Cortocircuito qui significa che la seconda condizione non verrà valutata.

Se (A & & B) si verificherà un cortocircuito se A è Falso.

Se (A & & B) sarà non risultato in corto circuito se A è vero.

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

Se (A || B) sarà non risultato in cortocircuito se A è Falso.

Problemi correlati