Court-circuitage de l'opérateur logique Java


100

Quel ensemble est en court-circuit et que signifie exactement le fait que l'expression conditionnelle complexe soit en court-circuit?

public static void main(String[] args) {
  int x, y, z;

  x = 10;
  y = 20;
  z = 30;

  // T T
  // T F
  // F T
  // F F

  //SET A
  boolean a = (x < z) && (x == x);
  boolean b = (x < z) && (x == z);
  boolean c = (x == z) && (x < z);
  boolean d = (x == z) && (x > z);
  //SET B    
  boolean aa = (x < z) & (x == x);
  boolean bb = (x < z) & (x == z);
  boolean cc = (x == z) & (x < z);
  boolean dd = (x == z) & (x > z);

}

Réponses:


244

Les opérateurs &&et ||"court-circuitent", ce qui signifie qu'ils n'évaluent pas le côté droit si ce n'est pas nécessaire.

Les opérateurs &et |, lorsqu'ils sont utilisés comme opérateurs logiques, évaluent toujours les deux côtés.

Il n'y a qu'un seul cas de court-circuit pour chaque opérateur, et ce sont:

  • false && ...- il n'est pas nécessaire de savoir ce qu'est le côté droit car le résultat ne peut être falseque quelle que soit la valeur là
  • true || ...- il n'est pas nécessaire de savoir ce qu'est le côté droit car le résultat ne peut être trueque quelle que soit la valeur là

Comparons le comportement dans un exemple simple:

public boolean longerThan(String input, int length) {
    return input != null && input.length() > length;
}

public boolean longerThan(String input, int length) {
    return input != null & input.length() > length;
}

La 2ème version utilise l'opérateur sans court-circuit &et lancera un NullPointerExceptionif inputis null, mais la 1ère version reviendra falsesans exception.


9
Je voudrais juste étendre un peu cette réponse. L'opérateur & = est un raccourci pour l'expression x = x &, et n'est donc PAS en court-circuit. Il en va de même pour l'opérateur | =.
Stormcloud du

11
Une chose que je voudrais souligner, | et & sont des opérateurs binaires, tandis que && et || sont des opérateurs conditionnels (logiques). | et & travailler sur plus que de simples booléens, while && et || ne fonctionne que sur les booléens.
Un mythe

1
Non seulement ils n'évaluent pas l'expression sur le côté droit, mais le code n'est pas exécuté pour qu'il y ait quelque chose à évaluer. Il s'agit d'un point critique pour comprendre si un effet secondaire serait autrement produit.
mckenzm

@mckenzm Quelle est la différence entre évalué et exécuté?
Kronen

@Kronen Execution peut entraîner plus que l'évaluation, et produire un effet secondaire, tel qu'une exception ou un retard, je paierai sans rapport avec cet exemple.
mckenzm

9

SET A utilise des opérateurs booléens de court-circuit.

Ce que signifie «court-circuit» dans le contexte des opérateurs booléens, c'est que pour un ensemble de booléens b1, b2, ..., bn, les versions de court-circuit cesseront d'être évaluées dès que le premier de ces booléens sera vrai (|| ) ou faux (&&).

Par exemple:

// 2 == 2 will never get evaluated because it is already clear from evaluating
// 1 != 1 that the result will be false.
(1 != 1) && (2 == 2)

// 2 != 2 will never get evaluated because it is already clear from evaluating
// 1 == 1 that the result will be true.
(1 == 1) || (2 != 2)

Veuillez préciser que c'est le cas pour &&, ||fonctionne différemment et arrêtera l'évaluation sur le premier opérande qui renvoie vrai;)
fge

1
En fait, pour être vraiment complet, tous &&, ||, &et |évaluer gauche à droite. Pour un ensemble de booléens b1, b2, ..., bn, les versions de court-circuit cesseront d'être évaluées lorsque le premier de ces booléens est vrai ( ||) ou faux ( &&). Bah, le principe est là;)
fge

@fge: Oui, vous avez raison bien sûr. Votre définition est supérieure à la mienne. J'ai mis à jour ma réponse avec la phrase dans votre commentaire. J'espère que cela ne vous dérange pas.
afrischke

Pas de soucis, la connaissance n'a aucune valeur si elle n'est pas partagée.
fge

4

Un court-circuit signifie que le deuxième opérateur ne sera pas vérifié si le premier opérateur décide du résultat final.

Par exemple, l'expression est: Vrai || Faux

Dans le cas de ||, tout ce dont nous avons besoin est l' un des côtés pour être vrai. Donc, si le côté gauche est vrai, il ne sert à rien de vérifier le côté droit, et par conséquent cela ne sera pas du tout vérifié.

De même, False && True

Dans le cas de &&, nous avons besoin que les deux côtés soient Vrai. Donc, si le côté gauche est Faux, il ne sert à rien de vérifier le côté droit, la réponse doit être False. Et par conséquent, cela ne sera pas du tout vérifié.


4
boolean a = (x < z) && (x == x);

Ce type court-circuitera, ce qui signifie que s'il est (x < z)évalué à faux, ce dernier n'est pas évalué, asera faux, sinon &&évaluera également (x == x).

& est un opérateur binaire, mais aussi un opérateur booléen AND qui ne court-circuite pas.

Vous pouvez les tester par quelque chose comme suit (voir combien de fois la méthode est appelée dans chaque cas):

public static boolean getFalse() {
    System.out.println("Method");
    return false;
}

public static void main(String[] args) {
    if(getFalse() && getFalse()) { }        
    System.out.println("=============================");        
    if(getFalse() & getFalse()) { }
}

-1 Votre réponse suggère que ce &n'est qu'un opérateur au niveau du bit, mais ce n'est pas vrai. C'est aussi un opérateur booléen "ou".
Bohème

@Bohemian: Merci pour la mise en garde. true & falsedonne la valeur false. Pouvez-vous expliquer cet "opérateur booléen" ou "opérateur"? Peut-être que je ne comprends pas ce que vous essayez de dire.
Bhesh Gurung

Désolé - je voulais dire booléen AND, non OR! c'est-à true & false- dire une syntaxe valide. -1 supprimé :)
Bohème

4

En termes simples, court-circuiter signifie arrêter l'évaluation une fois que vous savez que la réponse ne peut plus changer. Par exemple, si vous évaluez une chaîne de ANDs logiques et que vous découvrez un FALSEau milieu de cette chaîne, vous savez que le résultat sera faux, quelles que soient les valeurs du reste des expressions de la chaîne. Il en va de même pour une chaîne de ORs: une fois que vous découvrez a TRUE, vous connaissez la réponse tout de suite et vous pouvez donc ignorer l'évaluation du reste des expressions.

Vous indiquez à Java que vous souhaitez un court-circuit en utilisant &&au lieu de &et ||au lieu de |. Le premier ensemble de votre message est le court-circuit.

Notez que c'est plus qu'une tentative de sauvegarde de quelques cycles CPU: dans des expressions comme celle-ci

if (mystring != null && mystring.indexOf('+') > 0) {
    ...
}

un court-circuit signifie une différence entre un fonctionnement correct et un crash (dans le cas où mystring est nul).


2

Java fournit deux opérateurs booléens intéressants que l'on ne trouve pas dans la plupart des autres langages informatiques. Ces versions secondaires de AND et OR sont appelées opérateurs logiques de court-circuit . Comme vous pouvez le voir dans le tableau précédent, l'opérateur OR donne la valeur true lorsque A est vrai, quel que soit B.

De même, l'opérateur AND aboutit à false lorsque A est false, quel que soit B. Si vous utilisez les ||et &&formes, plutôt que les |et les &formes de ces opérateurs, Java ne dérangera pas d'évaluer la droite opérande seul. Ceci est très utile lorsque l'opérande de droite dépend du fait que l'opérande de gauche est vrai ou faux pour fonctionner correctement.

Par exemple, le fragment de code suivant montre comment vous pouvez tirer parti de l'évaluation logique de court-circuit pour être sûr qu'une opération de division sera valide avant de l'évaluer:

if ( denom != 0 && num / denom >10)

Comme la forme de court-circuit de AND ( &&) est utilisée, il n'y a aucun risque de provoquer une exception d'exécution en divisant par zéro. Si cette ligne de code était écrite en utilisant la &version unique de AND, les deux côtés devraient être évalués, provoquant une exception d'exécution lorsque denomvaut zéro.

Il est de pratique courante d'utiliser les formes de court-circuit de AND et OR dans les cas impliquant la logique booléenne, laissant les versions à un seul caractère exclusivement pour les opérations au niveau du bit. Cependant, il existe des exceptions à cette règle. Par exemple, considérez l'instruction suivante:

 if ( c==1 & e++ < 100 ) d = 100;

Ici, l'utilisation d'un seul &garantit que l'opération d'incrémentation sera appliquée selon equ'elle cest égale à 1 ou non.


2

OR logique: - renvoie vrai si au moins un des opérandes est évalué à vrai. Les deux opérandes sont évalués avant d'appliquer l'opérateur OR.

Court-circuit OU: - si l'opérande de gauche renvoie vrai, il renvoie vrai sans évaluer l'opérande de droite.


2

Il existe quelques différences entre les opérateurs &et &&. Les mêmes différences s'appliquent à |et ||. La chose la plus importante à garder à l'esprit est qu'il &&s'agit d'un opérateur logique qui ne s'applique qu'aux opérandes booléens, tandis qu'il &s'agit d'un opérateur au niveau du bit qui s'applique aux types entiers ainsi qu'aux booléens.

Avec une opération logique, vous pouvez effectuer un court-circuit car dans certains cas (comme le premier opérande d' &&être false, ou le premier opérande d' ||être true), vous n'avez pas besoin d'évaluer le reste de l'expression. Ceci est très utile pour faire des choses comme vérifier nullavant d'accéder à un fichier ou à une méthode, et vérifier les zéros potentiels avant de les diviser. Pour une expression complexe, chaque partie de l'expression est évaluée de manière récursive de la même manière. Par exemple, dans le cas suivant:

(7 == 8) || ( (1 == 3) && (4 == 4))

Seules les parties accentuées seront évaluées. Pour calculer le ||, vérifiez d'abord si 7 == 8est true. Si c'était le cas, le côté droit serait complètement ignoré. Le côté droit ne vérifie que si 1 == 3c'est le cas false. Comme c'est le cas, 4 == 4n'a pas besoin d'être vérifié, et l'expression entière est évaluée à false. Si le côté gauche était true, par exemple 7 == 7au lieu de 7 == 8, tout le côté droit serait ignoré car toute l' ||expression le serait trueindépendamment.

Avec une opération au niveau du bit, vous devez évaluer tous les opérandes car vous ne faites que combiner les bits. Les booléens sont en fait un entier d'un bit en Java (quel que soit le fonctionnement des éléments internes), et ce n'est qu'une coïncidence si vous pouvez faire un court-circuit pour les opérateurs au niveau du bit dans ce cas particulier. La raison pour laquelle vous ne pouvez pas court-circuiter un entier général &ou une |opération est que certains bits peuvent être activés et certains peuvent être désactivés dans l'un ou l'autre des opérandes. Quelque chose comme 1 & 2donne zéro, mais vous n'avez aucun moyen de le savoir sans évaluer les deux opérandes.


1
if(demon!=0&& num/demon>10)

Puisque la forme de court-circuit de ET (&&) est utilisée, il n'y a aucun risque de provoquer une exception d'exécution lorsque demon est nul.

Réf. Java 2 Fifth Edition par Herbert Schildt

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.