Cortocircuito dell'operatore logico Java


100

Quale set è in cortocircuito e cosa significa esattamente che l'espressione condizionale complessa è in cortocircuito?

public static void main(String[] args) {
  int x, y, z;

  x = 10;
  y = 20;
  z = 30;

  // T T
  // T F
  // F T
  // F F

  //SET A
  boolean a = (x < z) && (x == x);
  boolean b = (x < z) && (x == z);
  boolean c = (x == z) && (x < z);
  boolean d = (x == z) && (x > z);
  //SET B    
  boolean aa = (x < z) & (x == x);
  boolean bb = (x < z) & (x == z);
  boolean cc = (x == z) & (x < z);
  boolean dd = (x == z) & (x > z);

}

Risposte:


244

Gli operatori &&e ||"cortocircuitano", nel senso che non valutano il lato destro se non è necessario.

Gli operatori &e |, se usati come operatori logici, valutano sempre entrambi i lati.

C'è un solo caso di cortocircuito per ogni operatore e sono:

  • false && ...- non è necessario sapere quale sia il lato destro perché il risultato può essere solo falseindipendentemente dal valore lì
  • true || ...- non è necessario sapere quale sia il lato destro perché il risultato può essere solo trueindipendentemente dal valore lì

Confrontiamo il comportamento in un semplice esempio:

public boolean longerThan(String input, int length) {
    return input != null && input.length() > length;
}

public boolean longerThan(String input, int length) {
    return input != null & input.length() > length;
}

La seconda versione utilizza l'operatore di non cortocircuito &e lancerà un NullPointerExceptionif inputis null, ma la prima versione tornerà falsesenza eccezioni.


9
Vorrei solo estendere un po 'questa risposta. L'operatore & = è un'abbreviazione per x = x & espressione, e quindi NON è in cortocircuito. Lo stesso vale per l'operatore | =.
Stormcloud

11
Una cosa vorrei sottolineare, | e & sono operatori binari, mentre && e || sono operatori condizionali (logici). | e & lavorano su qualcosa di più dei semplici booleani, mentre && e || funziona solo su booleani.
Un mito il

1
Non solo non valutano l'espressione sul lato destro, il codice non viene eseguito perché ci sia qualcosa da valutare. Questo è un punto critico per capire se un effetto collaterale sarebbe altrimenti prodotto.
mckenzm

@mckenzm Qual è la differenza tra valutato ed eseguito?
Kronen,

L'esecuzione di @Kronen può portare a qualcosa di più della valutazione e produrre un effetto collaterale, come un'eccezione o un ritardo, pagherò non rilevante per questo esempio.
mckenzm

9

SET A utilizza operatori booleani di cortocircuito.

Il significato di "cortocircuito" nel contesto degli operatori booleani è che per un insieme di valori booleani b1, b2, ..., bn, le versioni in cortocircuito cesseranno di essere valutate non appena il primo di questi valori booleani sarà vero (|| ) o false (&&).

Per esempio:

// 2 == 2 will never get evaluated because it is already clear from evaluating
// 1 != 1 that the result will be false.
(1 != 1) && (2 == 2)

// 2 != 2 will never get evaluated because it is already clear from evaluating
// 1 == 1 that the result will be true.
(1 == 1) || (2 != 2)

Si prega di specificare che questo è il caso &&, ||funziona in modo diverso e interromperà la valutazione sul primo operando che restituisce true;)
fge

1
In realtà, per essere veramente completa, tutti &&, ||, &e |valuta da sinistra a destra. Per un insieme di valori booleani b1, b2, ..., bn, le versioni in cortocircuito cesseranno di essere valutati quando il primo di questi valori booleani è vero ( ||) o falso ( &&). Bah, il principio c'è;)
fge

@ fge: Sì, hai ragione ovviamente. La tua definizione è migliore della mia. Ho aggiornato la mia risposta con la frase nel tuo commento. Spero non ti dispiaccia.
afrischke

Nessun problema, la conoscenza non ha valore se non è condivisa.
fge

4

Il cortocircuito significa che il secondo operatore non sarà controllato se il primo operatore decide il risultato finale.

Ad esempio, l'espressione è: True || Falso

In caso di ||, tutto ciò di cui abbiamo bisogno è uno dei lati per essere True. Quindi, se il lato sinistro è vero, non ha senso controllare il lato destro, e quindi non verrà verificato affatto.

Allo stesso modo, False && True

In caso di &&, abbiamo bisogno che entrambi i lati siano True. Quindi, se il lato sinistro è Falso, non ha senso controllare il lato destro, la risposta deve essere Falso. E quindi questo non verrà verificato affatto.


4
boolean a = (x < z) && (x == x);

Questo tipo andrà in cortocircuito, il che significa che se (x < z)restituisce falso, quest'ultimo non viene valutato, asarà falso, altrimenti &&valuterà anche (x == x).

& è un operatore bit per bit, ma anche un operatore booleano AND che non va in cortocircuito.

Puoi testarli con qualcosa come segue (vedi quante volte il metodo viene chiamato in ogni caso):

public static boolean getFalse() {
    System.out.println("Method");
    return false;
}

public static void main(String[] args) {
    if(getFalse() && getFalse()) { }        
    System.out.println("=============================");        
    if(getFalse() & getFalse()) { }
}

-1 La tua risposta suggerisce che &è solo un operatore bit per bit, ma non è vero. È anche un operatore booleano "or".
Bohemian

@ Bohemian: grazie per l'avvertimento. true & falserestituisce false. Puoi spiegare questo "booleano" o "operatore"? Forse non sto ottenendo quello che stai cercando di dire.
Bhesh Gurung

Scusa, volevo dire booleano AND, no OR! cioè true & falseè una sintassi valida. -1 rimosso :)
Boemo

4

In parole povere, cortocircuitare significa interrompere la valutazione una volta che sai che la risposta non può più cambiare. Ad esempio, se stai valutando una catena di ANDs logiche e scopri un FALSEnel mezzo di quella catena, sai che il risultato sarà falso, indipendentemente dai valori del resto delle espressioni nella catena. Lo stesso vale per una catena di ORs: una volta scoperto a TRUE, conosci subito la risposta e quindi puoi saltare la valutazione del resto delle espressioni.

Indichi a Java che vuoi cortocircuitare usando &&invece di &e ||invece di |. Il primo set nel tuo post è il cortocircuito.

Nota che questo è più di un tentativo di salvare alcuni cicli della CPU: in espressioni come questa

if (mystring != null && mystring.indexOf('+') > 0) {
    ...
}

cortocircuito significa una differenza tra il corretto funzionamento e un crash (nel caso in cui mystring è nullo).


2

Java fornisce due interessanti operatori booleani non presenti nella maggior parte degli altri linguaggi per computer. Queste versioni secondarie di AND e OR sono note come operatori logici di cortocircuito . Come puoi vedere dalla tabella precedente, l'operatore OR risulta vero quando A è vero, indipendentemente da cosa sia B.

Allo stesso modo, l'operatore AND risulta falso quando A è falso, indipendentemente da cosa sia B. Se usi l'estensione||&& moduli e , invece di |e& moduli di questi operatori, Java non si preoccuperà di valutare solo l'operando di destra. Ciò è molto utile quando l'operando di destra dipende dal fatto che quello di sinistra sia vero o falso per funzionare correttamente.

Ad esempio, il seguente frammento di codice mostra come sfruttare la valutazione logica di cortocircuito per essere sicuri che un'operazione di divisione sarà valida prima di valutarla:

if ( denom != 0 && num / denom >10)

Poiché la forma di cortocircuito di AND (&& viene utilizzata la ), non vi è alcun rischio di causare un'eccezione di runtime dalla divisione per zero. Se questa riga di codice fosse scritta utilizzando la &versione singola di AND, entrambi i lati dovrebbero essere valutati, causando un'eccezione di runtime quando denomè zero.

È pratica standard utilizzare le forme di cortocircuito di AND e OR nei casi che coinvolgono la logica booleana, lasciando le versioni a carattere singolo esclusivamente per operazioni bit per bit. Tuttavia, ci sono eccezioni a questa regola. Ad esempio, considera la seguente dichiarazione:

 if ( c==1 & e++ < 100 ) d = 100;

Qui, l'utilizzo di un singolo &garantisce che l'operazione di incremento verrà applicata a ese cè uguale a 1 o meno.


2

OR logico: - restituisce vero se almeno uno degli operandi restituisce vero. Entrambi gli operandi vengono valutati prima di applicare l'operatore OR.

Cortocircuito OPPURE: - se l'operando del lato sinistro restituisce vero, restituisce vero senza valutare l'operando del lato destro.


2

Ci sono un paio di differenze tra gli operatori &e &&. Le stesse differenze si applicano a |e ||. La cosa più importante da tenere a mente è che &&è un operatore logico che si applica solo agli operandi booleani, mentre &è un operatore bit per bit che si applica ai tipi interi e ai booleani.

Con un'operazione logica si può cortocircuitare perché in certi casi (come il primo operando &&dell'essere false, o il primo operando ||dell'essere true), non è necessario valutare il resto dell'espressione. Questo è molto utile per fare cose come controllare nullprima di accedere a un file oa un metodo e controllare i potenziali zeri prima di dividerli. Per un'espressione complessa, ogni parte dell'espressione viene valutata in modo ricorsivo nello stesso modo. Ad esempio, nel caso seguente:

(7 == 8) || ( (1 == 3) && (4 == 4))

Verranno valutate solo le porzioni evidenziate. Per calcolare il ||, prima controlla se 7 == 8è true. Se lo fosse, il lato destro verrebbe saltato del tutto. Il lato destro controlla solo se lo 1 == 3è false. Poiché lo è, 4 == 4non è necessario verificarlo e l'intera espressione restituisce false. Se il lato sinistro fosse true, ad esempio, 7 == 7invece di 7 == 8, l'intero lato destro verrebbe saltato perché l'intera ||espressione sarebbe trueindipendentemente.

Con un'operazione bit per bit, è necessario valutare tutti gli operandi perché in realtà stai solo combinando i bit. I booleani sono effettivamente un numero intero a un bit in Java (indipendentemente da come funzionano gli interni), ed è solo una coincidenza che tu possa fare cortocircuiti per operatori bit a bit in quel caso speciale. Il motivo per cui non è possibile cortocircuitare un intero &o |un'operazione generale è che alcuni bit potrebbero essere attivi e altri potrebbero essere disattivati ​​in entrambi gli operandi. Qualcosa di simile 1 & 2produce zero, ma non hai modo di saperlo senza valutare entrambi gli operandi.


1
if(demon!=0&& num/demon>10)

Poiché viene utilizzata la forma di cortocircuito di AND (&&), non vi è alcun rischio di causare un'eccezione di runtime quando demon è zero.

Rif. Quinta edizione di Java 2 di Herbert Schildt

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.