Differenze negli operatori booleani: & vs && e | vs ||


Risposte:


134

Questi sono gli operatori AND bit per bit e OR bit per bit.

int a = 6; // 110
int b = 4; // 100

// Bitwise AND    

int c = a & b;
//   110
// & 100
// -----
//   100

// Bitwise OR

int d = a | b;
//   110
// | 100
// -----
//   110

System.out.println(c); // 4
System.out.println(d); // 6

Grazie a Carlos per aver indicato la sezione appropriata nelle specifiche del linguaggio Java ( 15.22.1 , 15.22.2 ) riguardante i diversi comportamenti dell'operatore in base ai suoi input.

Infatti, quando entrambi gli input sono booleani, gli operatori sono considerati gli operatori logici booleani e si comportano in modo simile agli operatori Conditional-And ( &&) e Conditional-Or ( ||) tranne per il fatto che non vanno in cortocircuito quindi mentre quanto segue è sicuro :

if((a != null) && (a.something == 3)){
}

Questo non è:

if((a != null) & (a.something == 3)){
}

"Cortocircuito" significa che l'operatore non esamina necessariamente tutte le condizioni. Negli esempi precedenti, &&esamineremo la seconda condizione solo quando anon lo è null(altrimenti l'intera istruzione restituirà false, e sarebbe comunque discutibile esaminare le seguenti condizioni), quindi l'affermazione di a.somethingnon solleverà un'eccezione o è considerata "sicura ".

L' &operatore esamina sempre ogni condizione nella clausola, quindi negli esempi precedenti, a.somethingpuò essere valutata quando aè in realtà un nullvalore, sollevando un'eccezione.


1
volevo chiarire .. & tornerà 1 solo se ENTRAMBI sono 1? Quindi 101 e 001 sarebbero 001? Destra?
gideon

@giddy @Jonathon - Ho aggiornato i miei valori per mostrare meglio quella situazione.
Justin Niessner

incompleti: sono anche operatori LOGICI (per booleani).
user85421

1
@ Carlos- No. Sono ancora operatori bit per bit. Si comportano semplicemente come gli operatori logici senza cortocircuito. C'è una differenza.
Justin Niessner

4
e quali sono gli operatori logici non cortocircuitanti? Gli operatori & e | (richiesto da OP) sono "Integer Bitwise Operators" (JLS 15.22.1) e "Boolean Logical Operators" (JLS 15.22.2). O la specifica del linguaggio Java è sbagliata?
user85421

108

Penso che tu stia parlando del significato logico di entrambi gli operatori, qui hai un curriculum tabella:

boolean a, b;

Operation     Meaning                       Note
---------     -------                       ----
   a && b     logical AND                    short-circuiting
   a || b     logical OR                     short-circuiting
   a &  b     boolean logical AND            not short-circuiting
   a |  b     boolean logical OR             not short-circuiting
   a ^  b     boolean logical exclusive OR
  !a          logical NOT

short-circuiting        (x != 0) && (1/x > 1)   SAFE
not short-circuiting    (x != 0) &  (1/x > 1)   NOT SAFE

La valutazione di cortocircuito , la valutazione minima o la valutazione di McCarthy (dopo John McCarthy) sono la semantica di alcuni operatori booleani in alcuni linguaggi di programmazione in cui il secondo argomento viene eseguito o valutato solo se il primo argomento non è sufficiente a determinare il valore del espressione: quando il primo argomento della funzione AND restituisce falso, il valore complessivo deve essere falso; e quando il primo argomento della funzione OR restituisce true, il valore complessivo deve essere true.

Non sicuro significa che l'operatore esamina sempre ogni condizione nella clausola, quindi negli esempi precedenti, 1 / x può essere valutato quando x è, in effetti, un valore 0, sollevando un'eccezione.


1
@ Torres - Si prega di espandere la risposta spiegando "cortocircuito" e "sicuro". Inoltre "esclusivo o" e "logico non" è anche "non cortocircuitato"? E perché si chiama "logico no" invece di "booleano logico no"? E perché il "NOT logico" non è raggruppato con "AND logico" e "OR logico"? Buona risposta ma necessita di lavori.
tfmontague

@tfmontague, ho spiegato cosa significa cortocircuito (modificando questa risposta) .. In attesa che la mia modifica sia "peer review".
Taslim Oseni

che cosa è "pericoloso" nel non cortocircuitare? non dovrebbe essere più sicuro che usare i cortocircuiti? btw: non spieghi davvero il termine "cortocircuito". significa che su "non cortocircuito" tutte le parti vengono prima valutate, quindi viene applicata l'operazione booleana, mentre su cortocircuito la valutazione viene interrotta, quando la prima espressione soddisfa la condizione, come (a || b) non lo farà valuta b, se a è vero e l'operazione or restituirà vero, indipendentemente da cosa sia b.
SCI

26

So che ci sono molte risposte qui, ma sembrano tutte un po 'confuse. Quindi, dopo aver fatto alcune ricerche dalla guida allo studio di Oracle Oracle, ho escogitato tre diversi scenari in cui utilizzare && o &. I tre scenari sono AND logico , AND bit per bit e AND booleano .

AND logico: AND logico (noto anche come AND condizionale) utilizza l' operatore && . Ha un significato cortocircuitato: se l'operando sinistro è falso, l'operando destro non verrà valutato.
Esempio:

int x = 0;
if (false && (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); // "0"

Nell'esempio sopra il valore stampato sulla console di x sarà 0, perché il primo operando nell'istruzione if è falso, quindi java non ha bisogno di calcolare (1 == ++ x) quindi x non verrà calcolato.

AND bit per bit: AND bit per bit utilizza l' operatore & . Viene utilizzato per eseguire un'operazione bit per bit sul valore. È molto più facile vedere cosa sta succedendo guardando le operazioni sui numeri binari es:

int a = 5;     //                    5 in binary is 0101
int b = 12;    //                   12 in binary is 1100
int c = a & b; // bitwise & preformed on a and b is 0100 which is 4

Come puoi vedere nell'esempio, quando le rappresentazioni binarie dei numeri 5 e 12 sono allineate, un AND bit per bit preformato produrrà solo un numero binario in cui la stessa cifra in entrambi i numeri ha un 1. Quindi 0101 e 1100 == 0100. Che in decimale è 5 e 12 == 4.

AND booleano: ora l'operatore AND booleano si comporta in modo simile e diverso sia per l'operatore AND bit per bit che per l'operatore AND logico. Mi piace pensare che preforma un AND bit per bit tra due valori booleani (o bit), quindi utilizza l' operatore & . Anche i valori booleani possono essere il risultato di un'espressione logica.

Restituisce un valore vero o falso, molto simile al logico AND, ma a differenza del logico AND non è in cortocircuito. Il motivo è che, per eseguire l'operatore AND bit per bit, deve conoscere il valore di entrambi gli operandi sinistro e destro. Ecco un ex:

int x = 0;
if (false & (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); //"1"

Ora, quando viene eseguita l'istruzione if, verrà eseguita l'espressione (1 == ++ x), anche se l'operando sinistro è falso. Quindi il valore stampato per x sarà 1 perché è stato incrementato.

Questo vale anche per OR logico (||), OR bit per bit (|) e OR booleano (|) Spero che questo chiarisca un po 'di confusione.


to preform that bitwise AND, it must know the value of both left and right operandsQuesto non mi sembra giusto. Per eseguire un BITWISE ANDnon è necessario conoscere l'operando di destra per poter capire il risultato se l'operando di sinistra è FALSE. Quello che spieghi è corretto, ma il ragionamento che dici non sembra così, almeno a me ..
Koray Tugay

7

Gli operatori && e || sono in corto circuito, nel senso che non valuteranno la loro espressione della mano destra se il valore dell'espressione della mano sinistra è sufficiente per determinare il risultato.


7
-1 per aver detto all'OP ciò che già sapeva e non aver risposto alla domanda che aveva effettivamente posto.
Alnitak

5

& e | forniscono lo stesso risultato di && e || operatori. La differenza è che valutano sempre entrambi i lati dell'espressione dove come && e || smettere di valutare se la prima condizione è sufficiente per determinare il risultato.


1
Sbagliato .... Perché &&valuta entrambi i risultati mentre ||restituisce solo se la prima condizione è vera.
Buhake Sindi

1
Eh? && valuta solo il lato destro dell'espressione se il lato sinistro è già vero. Altrimenti smette di valutare poiché il primo falso significa implicitamente che il risultato non può essere vero. Vedi jguru.com/faq/view.jsp?EID=16530
Brian Scott

1
( 2 & 4 )restituisce false, mentre ( 2 && 4 )restituisce true. In che modo esattamente è lo stesso risultato?
Piskvor ha lasciato l'edificio il

1
@Piskvor - non in Java! 2 & 4restituisce un numero intero, non un booleano (zero in questo caso). 2 && 4non verrà compilato, && accetta solo valori booleani. Java non consente di mescolare booleani e int: zero non è false, falsenon è zero ...
user85421

1
@BuhakeSindi Wrong. Perché &&valuta solo il secondo operando se il primo è true.
Marchese di Lorne

2

In Java, i singoli operatori &, |, ^,! dipendono dagli operandi. Se entrambi gli operandi sono interi, viene eseguita un'operazione bit per bit. Se entrambi sono booleani, viene eseguita un'operazione "logica".

Se entrambi gli operandi non corrispondono, viene generato un errore in fase di compilazione.

I doppi operatori &&, || si comportano in modo simile alle loro singole controparti, ma entrambi gli operandi devono essere espressioni condizionali, ad esempio:

if ((a <0) && (b <0)) {...} o similmente, if ((a <0) || (b <0)) {...}

fonte: programmazione java lang 4th ed



1

Forse può essere utile sapere che gli operatori AND bit per bit e OR bit per bit vengono sempre valutati prima di AND condizionale e OR condizionale utilizzati nella stessa espressione.

if ( (1>2) && (2>1) | true) // false!

1
intendi la priorità dell'operatore piuttosto che l'ordine di valutazione? Preferirei non vedere la differenza di priorità utilizzata nel codice reale. Utilizzare le parentesi anziché gli operatori bit per bit per questo scopo.
John Dvorak

1

&&; || sono operatori logici .... cortocircuito

&; | sono operatori logici booleani .... Non cortocircuito

Passando alle differenze nell'esecuzione delle espressioni. Gli operatori bit per bit valutano entrambi i lati indipendentemente dal risultato del lato sinistro. Ma nel caso della valutazione di espressioni con operatori logici, la valutazione dell'espressione della mano destra dipende dalla condizione della mano sinistra.

Per esempio:

int i = 25;
int j = 25;
if(i++ < 0 && j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

Questo stamperà i = 26; j = 25, poiché la prima condizione è falsa, la condizione della mano destra viene bypassata poiché il risultato è comunque falso indipendentemente dalla condizione del lato destro. (cortocircuito)

int i = 25;
int j = 25;
if(i++ < 0 & j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

Ma questo stamperà i = 26; j = 26,


0

Se viene valutata un'espressione che coinvolge l' operatore booleano & , vengono valutati entrambi gli operandi. Quindi l'operatore & viene applicato all'operando.

Quando viene valutata un'espressione che coinvolge l' operatore && , viene valutato il primo operando. Se il primo operando restituisce false, la valutazione del secondo operando viene ignorata.

Se il primo operando restituisce un valore true, viene valutato il secondo operando. Se il secondo operando restituisce un valore true, l'operatore && viene quindi applicato al primo e al secondo operando.

Simile per | e ||.


0

Mentre la differenza fondamentale è che &viene utilizzato per operazioni bit per bit principalmente su long, into bytedove può essere utilizzato per una sorta di maschera, i risultati possono differire anche se lo si utilizza invece di logica &&.

La differenza è più evidente in alcuni scenari:

  1. La valutazione di alcune delle espressioni richiede tempo
  2. La valutazione di una delle espressioni può essere eseguita solo se la precedente era vera
  3. Le espressioni hanno qualche effetto collaterale (intenzionale o meno)

Il primo punto è abbastanza semplice, non causa bug, ma richiede più tempo. Se hai diversi controlli in una sola istruzione condizionale, metti quelli che sono più economici o che hanno maggiori probabilità di fallire a sinistra.

Per il secondo punto, guarda questo esempio:

if ((a != null) & (a.isEmpty()))

Ciò non riesce null, poiché la valutazione della seconda espressione produce a NullPointerException. L'operatore logico &&è pigro, se l'operando di sinistra è falso, il risultato è falso indipendentemente dall'operando di destra.

Esempio per il terzo punto: supponiamo di avere un'app che utilizza DB senza trigger o cascate. Prima di rimuovere un oggetto Edificio, è necessario modificare l'edificio di un oggetto Reparto con un altro. Diciamo anche che lo stato dell'operazione viene restituito come booleano (vero = successo). Poi:

if (departmentDao.update(department, newBuilding) & buildingDao.remove(building))

Questo valuta entrambe le espressioni e quindi esegue la rimozione dell'edificio anche se l'aggiornamento del reparto non è riuscito per qualche motivo. Con &&, funziona come previsto e si ferma dopo il primo guasto.

Quanto a a || b, è equivalente a !(!a && !b), si ferma se aè vero, non è necessaria alcuna spiegazione.

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.