Effet d'un opérateur binaire sur un booléen en Java

118

Les opérateurs bit à bit sont censés parcourir les variables et les utiliser petit à petit. Dans le cas des entiers, des longs, des caractères, cela a du sens. Ces variables peuvent contenir la gamme complète de valeurs imposées par leur taille.

Dans le cas des booléens, cependant, un booléen ne peut contenir que deux valeurs. 1 = vrai ou 0 = faux. Mais la taille du booléen n'est pas définie. Il peut être aussi gros qu'un octet ou aussi petit.

Alors, quel est l'effet de l'utilisation d'un opérateur binaire sur un booléen? La JVM le traduit-il essentiellement en opérateur logique normal et passe-t-il à autre chose? Traite-t-il le booléen comme une entité à un seul bit aux fins de l'opération? Ou le résultat est-il indéfini avec la taille d'un booléen?

Daniel Bingham
la source
1
Je pense que vous ne pouvez pas utiliser un opérateur au niveau du bit sur un booléen. Uniquement sur les nombres. Je suis sûr que ~ ne fonctionnera pas, je ne sais pas pourquoi les autres opérateurs.
Martijn Courteaux
4
Vous pouvez en utiliser certains, nous venons de découvrir un | utilisé dans notre ancien code. Nous le supprimons, mais ce code a été compilé et a fonctionné.
Daniel Bingham
9
Puisque l'un est en court-circuit et l'autre non (voir la réponse de mobrule), avant de changer le | à || vous voudrez peut-être vous assurer que les expressions booléennes suivantes n'ont pas d'effets secondaires que le programmeur original avait l'intention de toujours exécuter.
John M Gant

Réponses:

122

Les opérateurs &, ^et |sont des opérateurs au niveau du bit lorsque les opérandes sont des types intégraux primitifs. Ce sont des opérateurs logiques lorsque les opérandes sont booléens, et leur comportement dans ce dernier cas est spécifié. Voir la section 15.22.2 de la spécification du langage Java pour plus de détails.

Noel Ang
la source
57
Plus précisément, & et ^ et | sont les opérateurs booléens logiques sans court-circuit.
Ken
14
Voici un lien direct vers la section mentionnée ci-dessus: docs.oracle.com/javase/specs/jls/se7/html/…
Andy Thomas
Si ce qui précède est vrai, pourquoi ideone.com/oGSF7c lève - t-il une exception de pointeur nul? Si l' |=opérateur était logique, le programme n'aurait jamais dû exécuter la x.getValue()directive.
ikromm
1
@JohnKrommidas, votre x est nul, c'est pourquoi vous obtenez une NullPointerException. Vous devez l'instancier.
Ben
4
@Ben, Comme le dit @Ken, la logique est sans court-circuit, donc la deuxième partie est évaluée. Donc, a || x.foo()c'est sûr si x est nul, mais a | x.foo()ne l'est pas. |=suit les mêmes règles que |.
Michael Smith
86

L'utilisation de l'opérateur au niveau du bit peut contourner le comportement de court-circuit:

boolean b = booleanExpression1() && booleanExpression2();
boolean b = booleanExpression1() & booleanExpression2();

Si booleanExpression1()évalue à false, alors
booleanExpression2()n'est pas évalué dans le premier cas, et
booleanExpression2()(et quels que soient les effets secondaires qu'il peut avoir) est évalué dans le second cas,

foule
la source
2
Et l'opération au niveau du bit est généralement plus rapide que celle en court-circuit (à condition que l'évaluation soit simple)
rds
1
Le bit &sera plus rapide, mais l'appel à la deuxième fonction pourrait être ignoré avec l'utilisation de&&
NatNgs
20

Au-delà de ce qui est couvert dans les autres réponses, il convient de le noter &&et d' ||avoir une priorité différente de &et |.

Extrait de la table de priorité (avec la priorité la plus élevée en haut).

bitwise AND                 &
bitwise exclusive OR        ^
bitwise inclusive OR        |
logical AND                 &&
logical OR                  ||

Qu'est-ce que cela signifie pour vous?

Absolument rien, tant que vous vous en tenez uniquement à &et |ou uniquement à &&et ||.

Mais, étant |donné que la priorité est plus élevée que &&(par opposition à ||, qui a une priorité inférieure), les mélanger librement pourrait conduire à un comportement inattendu.

C'est donc a && b | c && dla même chose que a && (b | c) && d,
par opposition à a && b || c && dqui serait (a && b) || (c && d).

Pour prouver qu'ils ne sont pas identiques, considérez un extrait de la table de vérité:

a | b | c | d | (b|c) | (a&&b) | (c&&d) | a && (b|c) && d | (a&&b) || (c&&d)
F | T | T | T |   T   |   F    |    T   |         F       |        T
                                                  ^                ^
                                                  |- not the same -|

Si vous voulez que OR ait une priorité plus élevée que AND, vous pouvez utiliser |et &&ensemble, mais ce n'est pas recommandé.

Mais vous devriez vraiment les mettre entre crochets pour clarifier la priorité chaque fois que vous utilisez des symboles différents, c'est-à-dire (a && b) || c(des crochets pour clarifier la priorité), a && b && c(pas de crochets nécessaires).

Bernhard Barker
la source
3

Même si cela fonctionne, vous ne devriez pas le faire. Les spécifications de langage définissent les opérateurs au niveau du bit uniquement lorsque les deux opérandes sont de types entiers primitifs ou les deux sont de type booléen. Je dirais que pour tout autre cas, les résultats ne sont pas définis:

http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5228

LeffeBrune
la source
La question est sur les booléens, pas primitives ou un mélange de primitives et booléens.
talonx le