Différences dans les opérateurs booléens: & vs && et | vs ||

Réponses:

134

Ce sont les opérateurs ET et OU au niveau du 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

Merci à Carlos d'avoir indiqué la section appropriée dans la spécification du langage Java ( 15.22.1 , 15.22.2 ) concernant les différents comportements de l'opérateur en fonction de ses entrées.

En effet, lorsque les deux entrées sont booléennes, les opérateurs sont considérés comme les opérateurs logiques booléens et se comportent de la même manière que les opérateurs Conditional-And ( &&) et Conditional-Or ( ||) à l'exception du fait qu'ils ne court-circuitent pas alors que ce qui suit est sûr :

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

Ce n'est pas:

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

«Court-circuit» signifie que l'opérateur n'examine pas nécessairement toutes les conditions. Dans les exemples ci-dessus, &&examinera la deuxième condition uniquement lorsque ce an'est pas le nullcas (sinon la déclaration entière retournera false, et il serait de toute façon inutile d'examiner les conditions suivantes), donc la déclaration de a.somethingne lèvera pas d'exception, ou est considérée comme "sûre . "

L' &opérateur examine toujours chaque condition de la clause, donc dans les exemples ci-dessus, a.somethingpeut être évalué quand aest en fait une nullvaleur, ce qui déclenche une exception.

Justin Niessner
la source
1
voulait clarifier .. & ne renverra 1 que si LES DEUX sont 1? Donc 101 & 001 seraient 001? Droite?
gideon
@giddy @Jonathon - J'ai mis à jour mes valeurs pour mieux montrer cette situation.
Justin Niessner
incomplet: ce sont aussi des opérateurs LOGIQUES (pour les booléens).
user85421
1
@ Carlos- Non. Ce sont toujours des opérateurs au niveau du bit. Ils se comportent simplement de la même manière que les opérateurs logiques sans court-circuit. Il existe une différence.
Justin Niessner
4
et quels sont les opérateurs logiques sans court-circuit? Les opérateurs & et | (demandé par OP) sont les "Opérateurs binaires entiers" (JLS 15.22.1) et les "Opérateurs logiques booléens" (JLS 15.22.2). Ou la spécification du langage Java est-elle erronée à ce sujet?
user85421
108

Je pense que vous parlez de la signification logique des deux opérateurs, ici vous avez un tableau-CV:

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

L'évaluation de court-circuit, l'évaluation minimale ou l'évaluation de McCarthy (d'après John McCarthy) est la sémantique de certains opérateurs booléens dans certains langages de programmation dans lesquels le deuxième argument est exécuté ou évalué uniquement si le premier argument ne suffit pas à déterminer la valeur du expression: lorsque le premier argument de la fonction AND prend la valeur false, la valeur globale doit être false; et lorsque le premier argument de la fonction OR est évalué à vrai, la valeur globale doit être vraie.

Not Safe signifie que l'opérateur examine toujours chaque condition de la clause, donc dans les exemples ci-dessus, 1 / x peut être évalué lorsque x est, en fait, une valeur 0, ce qui déclenche une exception.

Torres
la source
1
@Torres - Veuillez développer votre réponse en expliquant "court-circuit" et "sûr". Est-ce que "exclusif ou" et "logique n'est pas" aussi "pas court-circuit"? Et pourquoi est-il appelé «non logique» au lieu de «non logique booléen»? Et pourquoi le «NON logique» n'est-il pas groupé avec le «ET logique» et le «OU logique»? Bonne réponse mais a besoin de travail.
tfmontague
@tfmontague, j'ai expliqué ce que signifie le court-circuit (en éditant cette réponse) .. En attendant que ma modification soit "peer review".
Taslim Oseni
qu'est-ce qui est «dangereux» de ne pas court-circuiter? ne devrait-il pas être plus sûr que d'utiliser des courts-circuits? btw: vous n'expliquez pas vraiment le terme "court-circuit". cela signifie que sur "pas de court-circuit" toutes les pièces sont d'abord évaluées, puis l'opération booléenne est appliquée, tandis que sur court-circuit l'évaluation est arrêtée, lorsque la première expression satisfait la condition, comme (a || b) ne sera pas évaluez b, si a est vrai et que l'opération ou retournera vrai, quel que soit b.
SCI
26

Je sais qu'il y a beaucoup de réponses ici, mais elles semblent toutes un peu déroutantes. Donc, après avoir fait quelques recherches dans le guide d'étude Java oracle, j'ai proposé trois scénarios différents pour savoir quand utiliser && ou &. Les trois scénarios sont logiques et , au niveau du bit et booléen ET .

ET logique: ET logique (aka ET conditionnel) utilise l' opérateur && . C'est un sens court-circuité: si l'opérande gauche est faux, l'opérande droit ne sera pas évalué.
Exemple:

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

Dans l'exemple ci-dessus, la valeur imprimée sur la console de x sera 0, car le premier opérande de l'instruction if est faux, donc java n'a pas besoin de calculer (1 == ++ x) donc x ne sera pas calculé.

ET au niveau du bit: ET au niveau du bit utilise l' opérateur & . Il est utilisé pour effectuer une opération au niveau du bit sur la valeur. Il est beaucoup plus facile de voir ce qui se passe en regardant l'opération sur les nombres binaires ex:

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

Comme vous pouvez le voir dans l'exemple, lorsque les représentations binaires des nombres 5 et 12 sont alignées, alors un ET au niveau du bit préformé ne produira qu'un nombre binaire où le même chiffre dans les deux nombres aura un 1. Par conséquent 0101 & 1100 == 0100. Qui en décimal est 5 & 12 == 4.

Booléen AND: L'opérateur booléen AND se comporte désormais de manière similaire et différente à la fois au ET au niveau du bit et au ET logique. J'aime le penser comme préformant un ET au niveau du bit entre deux valeurs booléennes (ou bits), donc il utilise l' opérateur & . Les valeurs booléennes peuvent également être le résultat d'une expression logique.

Il renvoie une valeur vraie ou fausse, un peu comme le ET logique, mais contrairement au ET logique, il n'est pas court-circuité. La raison en est que pour préformer ce ET au niveau du bit, il doit connaître la valeur des opérandes gauche et droit. Voici un ex:

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

Maintenant, lorsque cette instruction if est exécutée, l'expression (1 == ++ x) sera exécutée, même si l'opérande de gauche est faux. Par conséquent, la valeur imprimée pour x sera 1 car elle a été incrémentée.

Ceci s'applique également aux OR logique (||), OR au niveau du bit (|) et OR booléen (|) J'espère que cela dissipe une certaine confusion.

LynchburgExplorateur
la source
to preform that bitwise AND, it must know the value of both left and right operandsCela ne me semble pas juste. Pour effectuer un, BITWISE ANDvous n'avez pas besoin de connaître l'opérande de droite pour pouvoir déterminer le résultat si l'opérande de gauche est FALSE. Ce que vous expliquez est correct, mais le raisonnement que vous énoncez ne me paraît pas le cas, du moins à moi.
Koray Tugay
7

Les opérateurs && et || sont en court-circuit, ce qui signifie qu'ils n'évalueront pas leur expression de droite si la valeur de l'expression de gauche est suffisante pour déterminer le résultat.

Tassos Bassoukos
la source
7
-1 pour avoir dit au PO ce qu'il savait déjà et ne pas avoir répondu à la question qu'il a réellement posée.
Alnitak
5

& et | fournissent le même résultat que les && et || les opérateurs. La différence est qu'ils évaluent toujours les deux côtés de l'expression où comme && et || arrêtez d'évaluer si la première condition est suffisante pour déterminer le résultat.

Brian Scott
la source
1
Wrong .... Car &&il évalue les deux résultats tandis qu'il ||ne renvoie que si la première condition est vraie.
Buhake Sindi
1
Hein? Le && évalue uniquement le côté droit de l'expression si le côté gauche est déjà évalué à vrai. Sinon, il arrête de s'évaluer car le premier faux signifie implicitement que le résultat ne peut pas être vrai. Voir jguru.com/faq/view.jsp?EID=16530
Brian Scott
1
( 2 & 4 )évalue à false, alors que ( 2 && 4 )évalue à true. En quoi exactement le même résultat?
Piskvor a quitté le bâtiment
1
@Piskvor - pas en Java! 2 & 4donne un entier et non un booléen (zéro dans ce cas). 2 && 4ne compilera pas, && n'acceptera que les booléens. Java ne permet pas de mélanger des booléens et des entiers: zéro n'est pas false, falsen'est pas zéro ...
user85421
1
@BuhakeSindi Wrong. Car &&il n'évalue le deuxième opérande que si le premier opérande l'est true.
Marquis of Lorne
2

En Java, les opérateurs uniques &, |, ^,! dépendent des opérandes. Si les deux opérandes sont des entiers, une opération au niveau du bit est effectuée. Si les deux sont des booléens, une opération "logique" est effectuée.

Si les deux opérandes ne correspondent pas, une erreur de compilation est générée.

Les opérateurs doubles &&, || se comportent de la même manière que leurs homologues simples, mais les deux opérandes doivent être des expressions conditionnelles, par exemple:

if ((a <0) && (b <0)) {...} ou similaire, if ((a <0) || (b <0)) {...}

source: programmation java lang 4th ed

aaron p.
la source
1

Peut-être qu'il peut être utile de savoir que les opérateurs binaires AND et binaires OR sont toujours évalués avant AND conditionnel et OR conditionnel utilisé dans la même expression.

if ( (1>2) && (2>1) | true) // false!
alexmeia
la source
1
voulez-vous dire la priorité de l'opérateur plutôt que l'ordre d'évaluation? Je préférerais ne pas voir la différence de priorité utilisée dans le code réel. Utilisez des parenthèses plutôt que des opérateurs au niveau du bit à cet effet.
John Dvorak
1

&&; || sont des opérateurs logiques ... court-circuit

&; | sont des opérateurs logiques booléens ... Non court-circuit

Passer aux différences d'exécution sur les expressions. Les opérateurs au niveau du bit évaluent les deux côtés indépendamment du résultat du côté gauche. Mais dans le cas de l'évaluation d'expressions avec des opérateurs logiques, l'évaluation de l'expression de droite dépend de la condition de gauche.

Par exemple:

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

Cela affichera i = 26; j = 25, comme la première condition est fausse, la condition de la main droite est contournée car le résultat est de toute façon faux quelle que soit la condition du côté droit. (court-circuit)

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

Mais, cela affichera i = 26; j = 26,

Nickhil
la source
0

Si une expression impliquant le booléen & opérateur est évaluée, les deux opérandes sont évalués. Ensuite, l'opérateur & est appliqué à l'opérande.

Lorsqu'une expression impliquant le && opérateur est évaluée, le premier opérande est évalué. Si le premier opérande est évalué à faux, l'évaluation du deuxième opérande est ignorée.

Si le premier opérande renvoie la valeur true, le deuxième opérande est évalué. Si le second opérande renvoie la valeur true, l'opérateur && est alors appliqué aux premier et second opérandes.

Similaire pour | et ||.

RishiKesh Pathak
la source
0

Bien que la différence fondamentale soit qu'elle &est utilisée pour les opérations au niveau du bit principalement sur long, intou bytelorsqu'elle peut être utilisée pour une sorte de masque, les résultats peuvent différer même si vous l'utilisez au lieu de&& .

La différence est plus notable dans certains scénarios:

  1. L'évaluation de certaines expressions prend du temps
  2. L'évaluation de l'une des expressions ne peut être effectuée que si la précédente était vraie
  3. Les expressions ont des effets secondaires (intentionnels ou non)

Le premier point est assez simple, il ne provoque aucun bogue, mais cela prend plus de temps. Si vous avez plusieurs vérifications différentes dans une instruction conditionnelle, placez celles qui sont moins chères ou plus susceptibles d'échouer à gauche.

Pour le deuxième point, voir cet exemple:

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

Cela échoue null, car l'évaluation de la deuxième expression produit un NullPointerException. L'opérateur logique &&est paresseux, si l'opérande gauche est faux, le résultat est faux quel que soit l'opérande droit.

Exemple pour le troisième point - disons que nous avons une application qui utilise DB sans aucun déclencheur ni cascades. Avant de supprimer un objet Building, nous devons remplacer le bâtiment d'un objet Department par un autre. Supposons également que l'état de l'opération soit renvoyé sous forme de valeur booléenne (vrai = succès). Ensuite:

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

Cela évalue les deux expressions et effectue ainsi la suppression du bâtiment même si la mise à jour du service a échoué pour une raison quelconque. Avec&& , cela fonctionne comme prévu et s'arrête après la première panne.

Quant à a || b, il équivaut à !(!a && !b), il s'arrête si ac'est vrai, aucune autre explication n'est nécessaire.

Vlasec
la source