2012-02-13 15 views
27

Quando utilizzato con boolean operandi, & e | diventa logici operatori per Section 15.22.2 of the JLS. A differenza di && e ||, tuttavia, questi non cortocircuitano; valuteranno sempre entrambi i lati. Ho una domanda sciocca: perché gli operatori logici non a corto circuito meno efficienti (&, |) sono ancora lì, quando abbiamo gli operatori logici di cortocircuito più efficienti (, ||)? Voglio dire, qual è il vero utilizzo degli operatori logici non a corto circuito, al contrario degli operatori logici a cortocircuito? In altre parole, a che serve valutare sempre entrambe le parti usando gli operatori logici senza cortocircuito?ragione dell'esistenza di operatori logici non-corto circuito

+6

Non si tratta di * efficienza *, hanno semantica * diversa * –

+2

È ciò che fa C./In realtà in alcune circostanze possono essere più veloci, perché possono ridurre la ramificazione. Ci possono anche essere effetti collaterali nella valutazione del rhs (il male). –

+1

@ TomHawtin-tackline: C non cortocircuita '&' e '|'. Come Java, cortocircuiti '&&' e '||', ma non '&' e '|'. –

risposta

25

risposta Aggiornato:

Scuse, ho perso la parola "logica" nella tua domanda, anche se èlì. (Ho preso la libertà di enfatizzare un po 'con una modifica.)

Si consideri il caso in cui si desidera effetti collaterali a sempre verificano, indipendentemente dal fatto che l'espressione di sinistra valuta true o false . Per esempio, il contrasto:

if (foo() & bar()) { 
    // Only call this if both operations returned true 
} 

con

if (foo() && bar()) { 
    // Only call this if both operations returned true 
} 

Si ipotizzi sia foo e bar hanno effetti che si vogliono avere accadere indipendentemente dal fatto che foo rendimenti true o false. Nella prima di sopra, I sa che bar verrà sempre chiamato e avrà il suo effetto. In quest'ultimo, ovviamente, bar può o non può essere chiamato. Se non avessimo la versione non-corto circuito, avremmo dovuto utilizzare le variabili temporanee:

boolean fooResult, barResult; 
fooResult = foo(); 
barResult = bar(); 
if (fooResult && barResult) { 
    // ... 
} 

Si potrebbe obiettare (probabilmente lo farei) che si dovrebbe fare che comunque, perché è così troppo facile da leggere in modo errato if (foo() & bar()), ma ci siamo, un motivo pragmatico per avere versioni senza cortocircuito.

risposta originale:

Come vi proponete & (o |) un operatore in corto circuito? Con && e ||, ha senso perché hai a che fare con condizioni booleane: possono essere vere o false, non ci sono sfumature di grigio. Ma & e | si occupano di bit, non di booleani. Il risultato è un numero. Voglio dire, suppongo che il & non possa valutare il lato destro se il lato sinistro fosse 0, e allo stesso modo | non potesse valutare se il lato sinistro fosse tutto-bit-on per qualunque fosse il tipo, ma io non vedo molto il punto di rendere significativo il caso limite di ciascun operatore (rispetto ai 254 o più altri casi).

+1

In Java e e | non funziona con i bit se applicato al tipo booleano. –

+0

@SuzanCioc: vero, giusto punto. –

+0

http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.22.2 –

1

È possibile avere alcuni effetti collaterali nell'espressione logica, ad esempio è possibile assegnare contemporaneamente al controllo. Questo potrebbe funzionare in modo errato se viene valutata solo una parte.

Non riesco a ricordare un buon esempio ora, ma ricordo che a volte avevo bisogno di operatori "non a corto circuito".

Hmmm .... Di seguito è ad esempio sbagliato, che non funziona senza "non-corto circuito" OR:

if((object1=getInstance1()).getNumber() == 1 || (object2=getInstance2()).getNumber() == 2) { 

    // do something which requires bot object1 and object2 assigned 

} 
+0

+1 per indicare "alcuni effetti collaterali nell'espressione logica". – namalfernandolk

10

Ci sono casi in cui i componenti di un'espressione booleana coinvolgono operazioni che avresti voluto aver eseguito in tutti i casi. Si consideri il seguente esempio di controllo di una password per la validità:

while (!password.isValid() & (attempts++ < MAX_ATTEMPTS)) { 

    // re-prompt 

} 

Se la seconda condizione non è stata valutata causa di un corto circuito, attempts sarebbe mai essere incrementato. In questo modo è possibile abilitare una maggiore flessibilità del programmatore.

+6

Ma questo può essere scritto con '&&' anche se cambia l'ordine :) –

0

Nel mio caso, ho due metodi che confrontano due oggetti diversi ma correlati (Object2 è un attributo di Object1) per vedere se ci sono stati cambiamenti. È necessario un aggiornamento se entrambi vengono aggiornati, ma entrambi devono essere valutati in modo che gli oggetti vengano modificati se entrambi sono stati modificati. Pertanto, è richiesto un confronto "OR" a tubo singolo.

EX:

if (compare(object1, currentObject1) | comparison(object2, currentObject2)) { 
    updateObject1(object1); 
} 
2

Il mio caso (C++):

void setFields(Parameters bundle) 
{ 
    if (setIfDifferent(&field1, bundle.value1) | 
     setIfDifferent(&field2, bundle.value2) | 
     setIfDifferent(&field3, bundle.value3)) { 
    storeState(); 
    } 
} 

setIfDifferent() imposta il campo dell'oggetto con nuovo valore se differiscono, nel qual caso restituisce true; o restituisce false nel caso in cui il campo e il nuovo valore siano gli stessi. Quindi, vogliamo provare a impostare tutti i campi, e se qualcuno di loro è cambiato, allora vogliamo memorizzare lo stato di un nuovo oggetto.

0

Tecnicamente, & e | non sono logici, sono operatori bit a bit che diventano operatori logici se associati ai booleani.

In alcuni casi è possibile includere espressioni di assegnazione all'interno delle espressioni logiche.

Di ':

if(a = (checkForSomeCondition()) | b = checkForAnotherCondition()) 
{ 
//now do something here with a and b that has been cached 
} 

Se avessi usato ||, io non sarei in grado di eseguire il controllo di cui sopra e avrei dovuto dividere le assegnazioni in dichiarazioni separate. Non ho mai incontrato scenari come questo durante lo sviluppo di applicazioni, ma l'ho incontrato poche volte durante la scrittura degli algoritmi.

Ovviamente, è possibile utilizzare gli operatori unari sulle espressioni logiche o passare le variabili per riferimento in un predicato, ma quelli sembrano casi meno comuni di quelli precedenti.

Problemi correlati