Est-ce une bonne pratique d'utiliser l'opérateur xor pour les vérifications booléennes? [fermé]

150

Personnellement , je aime l' exclusivité ou , ^, l' opérateur quand il est logique dans le contexte des contrôles booléens en raison de sa concision. Je préfère de loin écrire

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

que

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

mais je reçois souvent des regards confus de la part d'autres développeurs Java expérimentés (pas seulement les débutants), et parfois des commentaires sur la façon dont il ne devrait être utilisé que pour des opérations au niveau du bit.

Je suis curieux de connaître les meilleures pratiques concernant l'utilisation de l' ^opérateur.

Peter
la source

Réponses:

298

Vous pouvez simplement utiliser à la !=place.


la source
36
"Qu'est-ce qui ne va pas avec! =" A bool1 ^ bool2 ^ bool3 plus de sens pour moi quebool1 != bool2 != bool3
BlueRaja - Danny Pflughoeft
4
Mon cerveau me fait mal. Alors, est-ce que! = Peut donner des résultats incorrects ou non?
vemv
27
@vemv, !=donne des résultats corrects pour booleans (mais pas pour Booleans donc soyez prudent). Ce n'est pas toujours joli, par exemple, ce (some != null) != (other != null)n'est pas très lisible. Vous devez soit extraire les parties dans des booléens explicites, soit extraire le !=dans une méthode distincte.
ivant
23
Voici pourquoi: a ^ b=> "a ou b mais pas les deux", a != b=> "a n'est pas égal à b". (Ce que @RobertGrant a dit). La plupart des humains comprendraient le premier plus facilement s'ils savaient ce qu'est xor (ce qui est assez utile pour savoir si vous êtes dans le domaine de l'informatique ...)
Harold R. Eason
2
@ HaroldR.Eason important nitpicking ici: a != b=> "a n'est pas IDENTIQUE à b"
Mario Reutter
27

Je pense que vous avez répondu à votre propre question - si vous obtenez des regards étranges de la part des gens, il est probablement plus sûr d'opter pour l'option la plus explicite.

Si vous avez besoin de le commenter, vous feriez probablement mieux de le remplacer par la version plus verbeuse et de ne pas obliger les gens à poser la question en premier lieu.

Martin
la source
6
Je peux vous affirmer, vous obtiendrez des regards étranges de ma part, lorsque vous écrivez sérieusement (boolean1 && !boolean2) || (boolean2 && !boolean1)dans un code d'application de la vie réelle…
Holger
17

Je trouve que j'ai beaucoup de conversations similaires. D'une part, vous disposez d'une méthode compacte et efficace pour atteindre votre objectif. D'un autre côté, vous avez quelque chose que le reste de votre équipe pourrait ne pas comprendre, ce qui compliquera la maintenance à l'avenir.

Ma règle générale est de demander si la technique utilisée est quelque chose qu'il est raisonnable de s'attendre à ce que les programmeurs en général sachent. Dans ce cas, je pense qu'il est raisonnable de s'attendre à ce que les programmeurs sachent comment utiliser les opérateurs booléens, donc utiliser xor dans une instruction if est correct.

Comme exemple de quelque chose qui ne serait pas correct, prenez l'astuce d'utiliser xor pour échanger deux variables sans utiliser de variable temporaire. C'est une astuce que je ne m'attendrais pas à ce que tout le monde soit familier, donc cela ne passerait pas l'examen du code.

Dave Tarkowski
la source
14

Je pense que ce serait bien si vous le commentiez, par exemple // ^ == XOR.

Dre
la source
10

Vous pouvez toujours simplement l'envelopper dans une fonction pour lui donner un nom détaillé:

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

Mais, il me semble que ce ne serait pas difficile pour quiconque ne savait pas à quoi sert l'opérateur ^ de Google très rapidement. Ce ne sera pas difficile à retenir après la première fois. Puisque vous avez demandé d'autres utilisations, il est courant d'utiliser le XOR pour le masquage de bits.

Vous pouvez également utiliser XOR pour permuter les valeurs de deux variables sans utiliser de troisième variable temporaire .

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

Voici une question Stackoverflow liée à l'échange XOR .

Cory Gross
la source
6

J'ai récemment utilisé un xor dans un projet JavaScript au travail et j'ai fini par ajouter 7 lignes de commentaires pour expliquer ce qui se passait. La justification de l' utilisation XOR dans ce contexte est que l' un des termes ( term1dans l'exemple ci - dessous) pourrait prendre pas deux , mais trois valeurs: undefined, trueou falsealors que l'autre ( term2) pourrait être trueou false. J'aurais dû ajouter une vérification supplémentaire pour les undefinedcas mais avec xor, ce qui suit était suffisant car le xor force le premier terme à être d'abord évalué comme un booléen, laissant undefinedêtre traité comme false:

if (term1 ^ term2) { ...

C'était, à la fin, un peu exagéré, mais je voulais quand même le garder là-dedans, comme une sorte d'oeuf de Pâques.

Ates Goral
la source
À mon humble avis, au lieu de compter sur la conversion implicite, dans une situation inhabituelle à rencontrer, il est préférable de rendre la conversion explicite . Et en général, "laisser undefined être traité comme faux" est une pratique discutable dans n'importe quelle langue. Je n'ai pas utilisé de valeurs à trois états en java, mais en C #, une bool? avaleur peut être explicitement testée pour true en utilisant a == true- existe-t-il une technique similaire en java? En C #, étant donné deux bool?valeurs, "traiter null comme faux" conduirait à (a == true) ^ (b == true). Une formule équivalente est (a == true) != (b == true). Pouvez-vous faire quelque chose de similaire en java?
ToolmakerSteve
5
if((boolean1 && !boolean2) || (boolean2 && !boolean1)) 
{ 
  //do it 
} 

IMHO ce code pourrait être simplifié:

if(boolean1 != boolean2) 
{ 
  //do it 
} 
Y--
la source
5

En gardant à l'esprit la clarté du code, mon opinion est que l'utilisation de XOR dans les contrôles booléens n'est pas une utilisation typique de l'opérateur binaire XOR. D'après mon expérience, le XOR bit à bit en Java est généralement utilisé pour implémenter un flag togglecomportement de masque :

flags = flags ^ MASK;

Cet article de Vipan Singla explique le cas d'utilisation plus en détail.

Si vous avez besoin d'utiliser le XOR au niveau du bit comme dans votre exemple, expliquez pourquoi vous l'utilisez, car il est probable que même un public alphabétisé au niveau du bit s'arrête dans ses pistes pour comprendre pourquoi vous l'utilisez.

Gunnar Karlsson
la source
-1

Personnellement, je préfère l'expression "boolean1 ^ boolean2" en raison de sa concision.

Si j'étais dans votre situation (travaillant en équipe), je trouverais un compromis en encapsulant la logique "boolean1 ^ boolean2" dans une fonction avec un nom descriptif tel que "isDifferent (boolean1, boolean2)".

Par exemple, au lieu d'utiliser "boolean1 ^ boolean2", vous appelleriez "isDifferent (boolean1, boolean2)" comme ceci:

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

Votre fonction "isDifferent (boolean1, boolean2)" ressemblerait à ceci:

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

Bien sûr, cette solution implique l'utilisation d'un appel de fonction apparemment étranger, qui en soi est soumis à l'examen des meilleures pratiques, mais elle évite l'expression verbeuse (et moche) "(boolean1 &&! Boolean2) || (boolean2 &&! Boolean1) "!

UNE
la source
-2

Si le modèle d'utilisation le justifie, pourquoi pas? Bien que votre équipe ne reconnaisse pas immédiatement l'opérateur, elle le pourrait avec le temps. Les humains apprennent tout le temps de nouveaux mots. Pourquoi pas en programmation?

La seule mise en garde que je pourrais dire est que "^" n'a pas la sémantique de court-circuit de votre deuxième vérification booléenne. Si vous avez vraiment besoin de la sémantique des courts-circuits, une méthode util statique fonctionne également.

public static boolean xor(boolean a, boolean b) {
    return (a && !b) || (b && !a);
}
Alan
la source
16
Je ne vois pas de court-circuit possible avec xor - vous devez connaître à la fois a et b pour évaluer le résultat.
Thelema
7
De plus, les arguments seraient évalués au moment de l'appel, donc aucun court-circuit ne se produira.
erikkallen le
3
De plus, xor doit être une seule opération au niveau de la machine.
Ogre Psalm33
Vous devriez probablement rechercher la différence entre l'évaluation de court-circuit et l'évaluation paresseuse. L'évaluation short-curcuit est un style de code qui empêche les appels qui entraîneraient autrement des erreurs d'exécution, telles que la division par zéro. En C, cela peut être «si (dénominateur! = 0 && numérateur / dénominateur)», qui en lui-même utilise une évaluation paresseuse pour empêcher la division par zéro. Votre réponse est également purement spéculative.
Martin
2
Pour être honnête, un programmeur écrivant une fonction xor, qui fait exactement ce que fait l'opérateur xor mais de manière détournée, soulèverait plus de questions dans mon esprit (en particulier sur la compétence) qu'un programmeur qui vient d'utiliser ^.
Stijn de Witt le
-3

! = est OK pour comparer deux variables. Cela ne fonctionne pas, cependant, avec de multiples comparaisons.


la source
-3

En tant qu'opérateur au niveau du bit, xor est beaucoup plus rapide que tout autre moyen de le remplacer. Donc, pour les calculs de performances critiques et évolutifs, xor est impératif.

Mon opinion personnelle subjective: Il est absolument interdit, pour quelque raison que ce soit, d'utiliser l'égalité (== ou! =) Pour les booléens. Son utilisation montre un manque d'éthique et de principes fondamentaux de la programmation. Quiconque vous jette un regard confus sur ^ devrait être renvoyé aux bases de l'algèbre booléenne (j'ai été tenté d'écrire "aux rivières de la croyance" ici :)).

pseudo
la source
1
Sauf que le JIT est extrêmement bon pour les (petites) optimisations keyhole, comme le remplacement d'une expression booléenne par une autre.
David Leppik
1
De plus, ^ n'est pas principalement un opérateur booléen (logique), c'est un opérateur au niveau du bit. Il dit au lecteur de ralentir, car il y aura probablement des bogues de signe. Si vous utilisez ^ for! =, Vous allez être vraiment dérangé si jamais vous programmez en C.Les opérateurs binaires sont un signal à vos lecteurs (ceux qui déboguent votre code, vous y compris) de ralentir et de rechercher des erreurs de signe . Et ils peuvent être délicats. Par exemple, saviez-vous que le% de Java n'est pas un vrai modulo, comme en C ou Python? Une fois, j'ai eu un extrait de code qui fonctionnait de la même manière en C, JavaScript et Python, mais pas en Java.
David Leppik
6
Comment cela a-t-il été voté? Tout d'abord, en Java, XOR et! = Sont compilés [ stackoverflow.com/a/4175512/202504 . Avez-vous des chiffres pour étayer votre déclaration?
jmiserez
-4
str.contains("!=") ^ str.startsWith("not(")

me va mieux que

str.contains("!=") != str.startsWith("not(")
Chris Rea
la source