È buona norma utilizzare l'operatore xor per i controlli booleani? [chiuso]


150

Personalmente mi piace l' operatore esclusivo o , ^quando ha senso nel contesto dei controlli booleani a causa della sua concisione. Preferisco di gran lunga scrivere

if (boolean1 ^ boolean2)
{
  //do it
}

di

if((boolean1 && !boolean2) || (boolean2 && !boolean1))
{
  //do it
}

ma ricevo spesso sguardi confusi da altri sviluppatori Java esperti (non solo i neofiti), e talvolta commenti su come dovrebbe essere usato solo per operazioni bit a bit.

Sono curioso di sapere quali sono le migliori pratiche relative all'uso ^dell'operatore.

Risposte:


298

Puoi semplicemente usare !=invece.


36
"Cosa c'è che non va! =" bool1 ^ bool2 ^ bool3 Per me ha più senso logico dibool1 != bool2 != bool3
BlueRaja - Danny Pflughoeft

4
Mi fa male il cervello. Così può! = Produrre risultati errati o no?
Vemv,

27
@vemv, !=produce risultati corretti per booleans (ma non per Booleans, quindi fai attenzione). Non è sempre carino, ad esempio (some != null) != (other != null)non è molto leggibile. Devi estrarre le parti in booleani espliciti o estrarre il !=metodo in un metodo separato.
Ivant,

23
Ecco perché: a ^ b=> "a o b ma non entrambi", a != b=> "a non è uguale a b". (Cosa ha detto @RobertGrant). La maggior parte degli umani capirebbe il primo più semplice se sapessero cos'è xor (il che è abbastanza utile sapere se sei nel campo dell'informatica ...)
Harold R. Eason

2
@ HaroldR.Eason importante nitpicking qui: a != b=> "a non è IDENTICO per b"
Mario Reutter

27

Penso che tu abbia risposto alla tua domanda: se ottieni strani sguardi dalle persone, probabilmente è più sicuro scegliere l'opzione più esplicita.

Se devi commentarlo, probabilmente stai meglio sostituendolo con la versione più dettagliata e non facendo in modo che le persone facciano la domanda in primo luogo.


6
Posso affermarti che otterrai strani sguardi da me, quando scriverai seriamente (boolean1 && !boolean2) || (boolean2 && !boolean1)un codice di applicazione nella vita reale ...
Holger,

17

Trovo di avere conversazioni simili molto. Da un lato, hai un metodo compatto ed efficiente per raggiungere il tuo obiettivo. D'altra parte, hai qualcosa che il resto della tua squadra potrebbe non capire, rendendo difficile mantenere in futuro.

La mia regola generale è di chiedere se la tecnica utilizzata è qualcosa che è ragionevole aspettarsi che i programmatori in generale sappiano. In questo caso, penso che sia ragionevole aspettarsi che i programmatori sappiano come usare gli operatori booleani, quindi usare xor in un'istruzione if va bene.

Come esempio di qualcosa che non andrebbe bene, prendi il trucco di usare xor per scambiare due variabili senza usare una variabile temporanea. Questo è un trucco che non mi aspetto che tutti conoscano, quindi non passerebbe la revisione del codice.


14

Penso che andrebbe bene se lo commentassi, ad es // ^ == XOR.


10

Potresti sempre avvolgerlo in una funzione per dargli un nome dettagliato:

public static boolean XOR(boolean A, boolean B) {
    return A ^ B;
}

Ma, mi sembra che non sarebbe difficile per chiunque non sapesse a cosa l'operatore ^ sia molto veloce per Google. Non sarà difficile da ricordare dopo la prima volta. Poiché hai richiesto altri usi, è comune utilizzare XOR per il mascheramento dei bit.

Puoi anche usare XOR per scambiare i valori in due variabili senza usare una terza variabile temporanea .

// Swap the values in A and B
A ^= B;
B ^= A;
A ^= B;

Ecco una domanda StackOverflow relativa allo scambio XOR .


6

Di recente ho usato un xor in un progetto JavaScript al lavoro e ho finito per aggiungere 7 righe di commenti per spiegare cosa stava succedendo. La giustificazione per l'utilizzo xor in questo contesto è che uno dei termini ( term1nell'esempio qui sotto) potrebbe assumere non due ma tre valori: undefined, trueo falsementre l'altro ( term2) potrebbe essere trueo false. Avrei dovuto aggiungere un controllo aggiuntivo per i undefinedcasi, ma con xor, il seguente era sufficiente poiché lo xor forza il primo termine a essere valutato per la prima volta come un valore booleano, permettendo di undefinedessere trattato come false:

if (term1 ^ term2) { ...

Alla fine era un po 'eccessivo, ma volevo comunque tenerlo lì dentro, come una specie di uovo di Pasqua.


IMHO, invece di fare affidamento sulla conversione implicita, in una situazione insolita da incontrare, è meglio rendere esplicita la conversione . E in generale, "lasciare che gli indefiniti vengano trattati come falsi" è una pratica discutibile in qualsiasi lingua. Non ho usato valori tri-state in Java, ma in C #, un bool? avalore può essere esplicitamente testato per l'utilizzo vero a == true- esiste una tecnica simile in Java? In C #, dati due bool?valori, "trattare null come falso" porterebbe a (a == true) ^ (b == true). Una formula equivalente è (a == true) != (b == true). Puoi fare qualcosa di simile in Java?
ToolmakerSteve

5
if((boolean1 && !boolean2) || (boolean2 && !boolean1)) 
{ 
  //do it 
} 

IMHO questo codice potrebbe essere semplificato:

if(boolean1 != boolean2) 
{ 
  //do it 
} 

5

Con la chiarezza del codice in mente, la mia opinione è che l'uso di XOR nei controlli booleani non è un utilizzo tipico per l'operatore XOR bit a bit. Dalla mia esperienza, XOR bit a bit in Java viene generalmente utilizzato per implementare un flag togglecomportamento maschera :

flags = flags ^ MASK;

Questo articolo di Vipan Singla spiega in dettaglio il caso d'uso.

Se è necessario utilizzare XOR bit a bit come nell'esempio, commentare il motivo per cui lo si utilizza, poiché è probabile che anche un pubblico alfabetizzato a bit bit si fermi nelle proprie tracce per capire perché lo si sta utilizzando.


-1

Personalmente preferisco l'espressione "boolean1 ^ boolean2" per la sua succinta.

Se fossi nella tua situazione (lavorando in gruppo), colpirei un compromesso incapsulando la logica "boolean1 ^ boolean2" in una funzione con un nome descrittivo come "isDifferent (boolean1, boolean2)".

Ad esempio, invece di utilizzare "boolean1 ^ boolean2", chiameresti "isDifferent (boolean1, boolean2)" in questo modo:

if (isDifferent(boolean1, boolean2))
{
  //do it
}

La tua funzione "isDifferent (boolean1, boolean2)" sarebbe simile a:

private boolean isDifferent(boolean1, boolean2)
{
    return boolean1 ^ boolean2;
}

Ovviamente, questa soluzione implica l'uso di una chiamata di funzione apparentemente estranea, che di per sé è soggetta al controllo delle Best Practices, ma evita l'espressione verbosa (e brutta) "(boolean1 &&! Boolean2) || (boolean2 &&! Boolean1) "!


-2

Se il modello di utilizzo lo giustifica, perché no? Mentre la tua squadra non riconosce subito l'operatore, con il tempo potrebbe. Gli umani imparano sempre nuove parole. Perché non in programmazione?

L'unica avvertenza che potrei affermare è che "^" non ha la semantica di corto circuito del tuo secondo controllo booleano. Se hai davvero bisogno della semantica del corto circuito, funziona anche un metodo util statico.

public static boolean xor(boolean a, boolean b) {
    return (a && !b) || (b && !a);
}

16
Non vedo alcun corto circuito possibile con xor - devi conoscere sia a che b per valutare il risultato.
Thelema,

7
Inoltre, gli argomenti verrebbero valutati al momento della chiamata, quindi non si verificherà alcun cortocircuito.
erikkallen,

3
Inoltre, xor dovrebbe essere una singola operazione a livello di macchina.
Ogre Salmo33

Probabilmente dovresti cercare la differenza tra valutazione del corto circuito e valutazione pigra. La valutazione short-curcuit è uno stile di codice che impedisce le chiamate che altrimenti comporterebbero errori di runtime, come la divisione per zero. In C questo può essere ´if (denominatore! = 0 && numeratore / denominatore) ´, che in sé utilizza una valutazione lenta per impedire la divisione per zero. Anche la tua risposta è puramente speculativa.
Martin,

2
Ad essere sincero, un programmatore che scrive una funzione xor, che fa esattamente quello che fa l'operatore xor ma in modo indiretto, mi farebbe sorgere più domande (in particolare sulla competenza) di un programmatore che ha appena usato ^.
Stijn de Witt,

-3

! = è OK per confrontare due variabili. Non funziona, tuttavia, con confronti multipli.


-3

Come operatore bit per bit, xor è molto più veloce di qualsiasi altro mezzo per sostituirlo. Quindi, per calcoli critici e scalabili in termini di prestazioni, xor è indispensabile.

La mia opinione personale soggettiva: è assolutamente vietato, per qualsiasi scopo, usare l'uguaglianza (== o! =) Per i booleani. Usarlo mostra la mancanza di etica e fondamenti della programmazione di base. Chiunque ti dia uno sguardo confuso ^ dovrebbe essere rispedito alle basi dell'algebra booleana (ero tentato di scrivere "ai fiumi della fede" qui :)).


1
Tranne il fatto che JIT è estremamente bravo nelle ottimizzazioni (poco) del buco della serratura, come la sostituzione di un'espressione booleana con un'altra.
David Leppik,

1
Inoltre, ^ non è principalmente un operatore booleano (logico), è un operatore bit per bit. Indica al lettore di rallentare, perché è probabile che si verifichino bug dei segni. Se usi ^ for! =, Verrai davvero incasinato se programmerai mai in C. Gli operatori bit a bit sono un segnale per i tuoi lettori (quelli che eseguono il debug del tuo codice, incluso te) per rallentare e cercare errori di segno . E possono essere difficili. Ad esempio, sapevi che% di Java non è vero modulo, come in C o Python? Una volta avevo uno snippet di codice che funzionava allo stesso modo in C, JavaScript e Python, ma non in Java.
David Leppik,

6
Come è mai stato votato? Prima di tutto, in Java XOR e! = Sono compilati [ stackoverflow.com/a/4175512/202504× ( esattamente lo stesso codice), secondo anche nei test assembler per l'uguaglianza e xor sono singole semplici operazioni ciascuna. Hai dei numeri per il backup della tua dichiarazione?
jmiserez,

-4
str.contains("!=") ^ str.startsWith("not(")

mi sembra meglio di

str.contains("!=") != str.startsWith("not(")
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.