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

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

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

Java controllerebbe b se a è falso nel primo caso e se a è vero nel secondo caso?

No, non sarà valutato. E questo è molto utile. Ad esempio, se è necessario verificare se una stringa non è nulla o vuota, è ansible 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 i “cortocircuiti” in Java, avremmo ricevuto molte NullPointerException nelle linee di codice di cui sopra.

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

& e && sono “e” operatori, | 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 di sinistra e il suo valore e se true ( || ) o false ( && ) non && il secondo. Suono compilato? Un semplice esempio dovrebbe chiarire:

Dati 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 restituisce false , quindi il secondo parametro non verrà controllato, perché il risultato è comunque false .

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 restituisce true , quindi il secondo parametro non verrà controllato, perché il risultato è comunque true .

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

No, non verrà controllato. Questo comportamento è chiamato valutazione di cortocircuito ed è una funzionalità in molte lingue incluso Java.

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.

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

L’operatore && è come & (§15.22.2), ma valuta il suo operando di 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. Quindi, && calcola lo stesso risultato di & su operandi booleani. Differisce solo nel fatto che l’espressione dell’operando di destra è valutata condizionalmente piuttosto che sempre.

Analogamente, la Sezione 15:24, Operatore condizionale-O (||) , dice:

|| 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 la ‘metà’ appropriata (metà sinistra se il valore è true, metà destra se è false), consentendo l’uso di espressioni come:

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

senza NullPointerException.

No, se a è vero (in a or test), b non sarà 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")) { ... } 

non lancia una NullPointerException !

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

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

Un fatto interessante è che anche Java usa & e | come operandi logici (sono sovraccarichi, con tipi int sono le operazioni bitwise previste) per valutare tutti i termini nell’espressione, che è anche utile quando sono necessari gli effetti collaterali.

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

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

Se (A && B) non provocherà cortocircuito se A è vero.

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

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

Questo risale alla differenza fondamentale tra & e &&, | e ||

A proposito si svolgono le stesse attività 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); }