java freshdesk - Perché di solito usiamo `||` non `|`, qual è la differenza?




13 Answers

Se usi il || e && form, piuttosto che | e le forme di questi operatori, Java non si preoccuperà di valutare da solo l'operando di destra.

È una questione di se si vuole cortocircuitare la valutazione o meno - la maggior parte del tempo che si desidera.

Un buon modo per illustrare i vantaggi del cortocircuito sarebbe considerare il seguente esempio.

Boolean b = true;
if(b || foo.timeConsumingCall())
{
   //we entered without calling timeConsumingCall()
}

Un altro vantaggio, come hanno detto Jeremy e Peter, per il cortocircuito è il controllo di riferimento null:

if(string != null && string.isEmpty())
{
    //we check for string being null before calling isEmpty()
}

Ulteriori informazioni

api rfc

Mi sto solo chiedendo perché usiamo normalmente OR || tra due booleani non a bit OR | , anche se stanno entrambi lavorando bene.

Voglio dire, guarda quanto segue:

if(true  | true)  // pass
if(true  | false) // pass
if(false | true)  // pass
if(false | false) // no pass
if(true  || true)  // pass
if(true  || false) // pass
if(false || true)  // pass
if(false || false) // no pass

Possiamo usare | invece di || ? Stessa cosa con & e && .




Quindi, basandoci sulle altre risposte con un esempio, il cortocircuito è cruciale nei seguenti controlli difensivi:

if (foo == null || foo.isClosed()) {
    return;
}

if (bar != null && bar.isBlue()) {
    foo.doSomething();
}

Utilizzando | e invece potrebbe dare luogo a una NullPointerException lanciata qui.




Notate anche una trappola comune: gli operatori non pigri hanno la precedenza su quelli pigri, quindi:

boolean a, b, c;
a || b && c; //resolves to a || (b && c)
a | b && c; //resolves to (a | b) && c

Fai attenzione quando li mescoli.




L'unica volta che useresti | o & invece di || o && è quando si hanno espressioni booleane molto semplici e il costo del taglio breve (cioè un ramo) è maggiore del tempo risparmiato non valutando le espressioni successive.

Tuttavia, si tratta di una micro-ottimizzazione che raramente conta tranne nel codice di livello più basso.




In aggiunta al fatto che | è un operatore bit a bit: || è un operatore di cortocircuito: quando un elemento è falso, non controlla gli altri.

 if(something || someotherthing)
 if(something | someotherthing)

se qualcosa è VERO, || non valuterà qualcosa di simile, mentre | andrà bene. Se le variabili nelle tue if-statement sono effettivamente chiamate di funzione, usando || è possibile risparmiare un sacco di prestazioni.




| is the binary or operator

|| is the logic or operator



Una nota a margine: Java ha | = ma non un || =

Un esempio di quando devi usare || è quando la prima espressione è un test per vedere se la seconda espressione esploderebbe. ad es. usando un singolo | nel seguente caso potrebbe risultare in un NPE.

public static boolean isNotSet(String text) {
   return text == null || text.length() == 0;
}



Una differenza principale è che || e && esibire "cortocircuito", quindi l'RHS verrà valutato solo se necessario.

Per es

if (a || b) {
    path1...
} else {
    path2..
}

Sopra se a è vero allora b non verrà testato e il percorso 1 verrà eseguito. Se | è stato usato quindi entrambi i lati sarebbero stati valutati anche se 'a' fosse vero.

Vedi Here e here , per un po 'più di informazioni.

Spero che questo ti aiuti.




Le altre risposte hanno svolto un buon lavoro coprendo la differenza funzionale tra gli operatori, ma le risposte potrebbero applicarsi a quasi ogni singolo linguaggio derivato da C esistente oggi. La domanda è contrassegnata con java , quindi cercherò di rispondere in modo specifico e tecnico per il linguaggio Java.

& e | può essere Operatore bit per bit intero o Operatore logico booleano. La sintassi per gli operatori §15.22 e logici ( §15.22 ) è:

AndExpression:
  EqualityExpression 
  AndExpression & EqualityExpression

ExclusiveOrExpression:
  AndExpression 
  ExclusiveOrExpression ^ AndExpression

InclusiveOrExpression:
  ExclusiveOrExpression 
  InclusiveOrExpression | ExclusiveOrExpression

La sintassi per EqualityExpression è definita in §15.21 , che richiede RelationalExpression definita in §15.20 , che a sua volta richiede ShiftExpression e ReferenceType definiti in §15.19 e §4.3 , rispettivamente. ShiftExpression richiede AdditiveExpression definita in §15.18 , che continua con il drill-down, definendo l'aritmetica di base, gli operatori unari, ecc. ReferenceType esegue il drill down in tutti i vari modi per rappresentare un tipo. (Sebbene ReferenceType non includa i tipi primitivi, la definizione di tipi primitivi è in definitiva necessaria, in quanto possono essere il tipo di dimensione per un array, che è un ReferenceType .)

Gli operatori bit a bit e logici hanno le seguenti proprietà:

  • Questi operatori hanno precedenza diversa, con & avendo la precedenza più alta e | la precedenza più bassa.
  • Ciascuno di questi operatori è sintatticamente associato a sinistra (ogni gruppo da sinistra a destra).
  • Ogni operatore è commutativo se le espressioni di operando non hanno effetti collaterali.
  • Ogni operatore è associativo.
  • Gli operatori bit a bit e logici possono essere utilizzati per confrontare due operandi di tipo numerico o due operandi di tipo boolean . Tutti gli altri casi generano un errore in fase di compilazione.

La distinzione tra se l'operatore funge da operatore bit a bit o operatore logico dipende dal fatto che gli operandi siano "convertibili in un tipo integrale primitivo" ( §4.2 ) o se siano di tipo boolean o Boolean ( §5.1.8 ).

Se gli operandi sono tipi interi, la promozione numerica binaria ( §5.6.2 ) viene eseguita su entrambi gli operandi, lasciandoli entrambi come long s o int s per l'operazione. Il tipo dell'operazione sarà il tipo degli operandi (promossi). A quel punto, & sarà bit a AND, ^ sarà bit esclusivo OR, e | sarà bit a bit compreso OR. ( §15.22.1 )

Se gli operandi sono boolean o Boolean , gli operandi saranno soggetti alla conversione di unboxing, se necessario ( §5.1.8 ), e il tipo dell'operazione sarà boolean . & risulterà true se entrambi gli operandi sono true , ^ risulterà true se entrambi gli operandi sono diversi e | risulterà true se uno degli operandi è true . ( §15.22.2 )

Al contrario, && è il "Conditional-And Operator" ( §15.23 ) e || è il "Conditional-Or Operator" ( §15.24 ). La loro sintassi è definita come:

ConditionalAndExpression:
  InclusiveOrExpression 
  ConditionalAndExpression && InclusiveOrExpression

ConditionalOrExpression:
  ConditionalAndExpression 
  ConditionalOrExpression || ConditionalAndExpression

&& è come & , tranne che valuta solo l'operando di destra se l'operando di sinistra è true . || è come | , eccetto che valuta solo l'operando di destra se l'operando di sinistra è false .

Condizionale-E ha le seguenti proprietà:

  • L'operatore condizionale e sintatticamente è associato a sinistra (si raggruppa da sinistra a destra).
  • L'operatore condizionale-e è completamente associativo rispetto agli effetti collaterali e al valore del risultato. Cioè, per qualsiasi espressione a , b , e c , la valutazione dell'espressione ((a) && (b)) && (c) produce lo stesso risultato, con gli stessi effetti collaterali che si verificano nello stesso ordine, come valutazione del espressione (a) && ((b) && (c)) .
  • Ogni operando dell'operatore condizionale e deve essere di tipo boolean o Boolean oppure si verifica un errore in fase di compilazione.
  • Il tipo di condizionale e l'espressione è sempre boolean .
  • In fase di esecuzione, l'espressione dell'operando di sinistra viene valutata per prima; se il risultato ha tipo Boolean , viene sottoposto alla conversione di unboxing ( §5.1.8 ).
  • Se il valore risultante è false , il valore del condizionale e dell'espressione è false e l'espressione dell'operando di destra non viene valutata.
  • Se il valore dell'operando di sinistra è true , viene valutata l'espressione di destra; se il risultato ha tipo Boolean , viene sottoposto alla conversione di unboxing ( §5.1.8 ). Il valore risultante diventa il valore dell'espressione e condizionale.
  • Quindi, && calcola lo stesso risultato di & su operandi boolean . Differisce solo nel fatto che l'espressione dell'operando di destra è valutata condizionalmente piuttosto che sempre.

Condizionale-O ha le seguenti proprietà:

  • L'operatore condizionale o sintatticamente è associato a sinistra (si raggruppa da sinistra a destra).
  • L'operatore condizionale o è completamente associativo rispetto agli effetti collaterali e al valore del risultato. Cioè, per qualsiasi espressione a , b , e c , valutazione dell'espressione ((a) || (b)) || (c) ((a) || (b)) || (c) produce lo stesso risultato, con gli stessi effetti collaterali che si verificano nello stesso ordine, come valutazione dell'espressione (a) || ((b) || (c)) (a) || ((b) || (c)) .
  • Ogni operando dell'operatore condizionale o deve essere di tipo boolean o Boolean oppure si verifica un errore in fase di compilazione.
  • Il tipo di condizionale o espressione è sempre boolean .
  • In fase di esecuzione, l'espressione dell'operando di sinistra viene valutata per prima; se il risultato ha tipo Boolean , viene sottoposto alla conversione di unboxing ( §5.1.8 ).
  • Se il valore risultante è true , il valore dell'espressione condizionale o è true e l'espressione dell'operando di destra non viene valutata.
  • Se il valore dell'operando di sinistra è false , viene valutata l'espressione di destra; se il risultato ha tipo Boolean , viene sottoposto alla conversione di unboxing ( §5.1.8 ). Il valore risultante diventa il valore dell'espressione condizionale o.
  • Quindi, || calcola lo stesso risultato di | su operandi boolean o Boolean . Differisce solo nel fatto che l'espressione dell'operando di destra è valutata condizionalmente piuttosto che sempre.

In breve, come @JohnMeagher ha più volte sottolineato nei commenti, & e | sono, infatti, operatori booleani non in cortocircuito nel caso specifico degli operandi sia boolean che Boolean . Con buone pratiche (es: senza effetti secondari), questa è una piccola differenza. Tuttavia, quando gli operandi non sono boolean o Boolean , gli operatori si comportano in modo molto diverso: le operazioni bit a bit e quelle logiche semplicemente non si confrontano bene con l'alto livello della programmazione Java.




| = bit a bit o, || = logica o




Ci sono molti casi d'uso che suggeriscono perché dovresti andare per || piuttosto che | . Alcuni casi d'uso devono usare | operatore per verificare tutte le condizioni.

Ad esempio, se si desidera verificare la convalida del modulo e si desidera mostrare all'utente tutti i campi non validi con testi di errore anziché solo un primo campo non valido.

|| l'operatore sarebbe,

   if(checkIfEmpty(nameField) || checkIfEmpty(phoneField) || checkIfEmpty(emailField)) {
      // invalid form with one or more empty fields
   }

   private boolean checkIfEmpty(Widget field) {
      if(field.isEmpty()) {
        field.setErrorMessage("Should not be empty!");
        return true;
      }
      return false;
   }

Quindi, con lo snippet sopra riportato, se l'utente invia il modulo con TUTTI i campi vuoti, SOLO nameField verrà mostrato con un messaggio di errore. Ma se lo cambi,

   if(checkIfEmpty(nameField) | checkIfEmpty(phoneField) | checkIfEmpty(emailField)) {
      // invalid form with one or more empty fields
   }

Mostrerà il messaggio di errore corretto su ciascun campo indipendentemente dalle condizioni true .




|| è un logico o e | è un po 'saggio o.







Related