web-dev-qa-db-fra.com

&& (AND) et || (OU) dans les instructions IF

J'ai le code suivant:

if(!partialHits.get(req_nr).containsKey(z) || partialHits.get(req_nr).get(z) < tmpmap.get(z)){  
    partialHits.get(z).put(z, tmpmap.get(z));  
}

partialHits est un HashMap.
Que se passera-t-il si la première déclaration est vraie?Est-ce que Java vérifiera toujours la deuxième déclaration? Parce que, dans l'ordre, la première déclaration soit vrai, le HashMap ne devrait pas contenir la clé donnée, donc si la deuxième instruction est cochée, je vais obtenir NullPointerException.
Donc, en termes simples, si nous avons le code suivant

if(a && b)  
if(a || b)

Java vérifierait-il b si a est faux dans le premier cas et si a est vrai dans le deuxième cas?

123
Azimuth

Non, cela ne sera pas évalué. Et c'est très utile. Par exemple, si vous devez vérifier si une chaîne n'est pas nulle ou vide, vous pouvez écrire:

if (str != null && !str.isEmpty()) {
  doSomethingWith(str.charAt(0));
}

ou l'inverse

if (str == null || str.isEmpty()) {
  complainAboutUnusableString();
} else {
  doSomethingWith(str.charAt(0));
}

Si nous n'avions pas de "courts-circuits" en Java, nous recevrions beaucoup d'exceptions NullPointerExceptions dans les lignes de code ci-dessus.

187
Andreas_D

Java a 5 opérateurs de comparaison booléens différents: &, &&, |, ||, ^

& et && sont des opérateurs "et", | et || "ou" opérateurs, ^ est "xor"

Les simples vérifieront chaque paramètre, quelles que soient les valeurs, avant de vérifier les valeurs des paramètres. Les doubles vont d'abord vérifier le paramètre de gauche et sa valeur et si true (||) ou false (&&) laisse le second intact. Le son compilé? Un exemple simple devrait préciser:

donné pour tous les exemples:

 String aString = null;

ET:

 if (aString != null & aString.equals("lala"))

Les deux paramètres sont vérifiés avant la fin de l'évaluation et une exception NullPointerException sera levée pour le deuxième paramètre.

 if (aString != null && aString.equals("lala"))

Le premier paramètre est vérifié et renvoie false. Par conséquent, le deuxième paramètre ne sera pas vérifié, car le résultat est de toute façon false.

Même chose pour OR:

 if (aString == null | !aString.equals("lala"))

Lève une exception NullPointerException également.

 if (aString == null || !aString.equals("lala"))

Le premier paramètre est vérifié et renvoie true. Par conséquent, le deuxième paramètre ne sera pas vérifié, car le résultat est de toute façon true.

XOR ne peut pas être optimisé, car cela dépend des deux paramètres.

64
Hardcoded

Non, cela ne sera pas vérifié. Ce comportement s'appelle évaluation de court-circuit et est une fonctionnalité disponible dans de nombreux langages, y compris Java.

26

Toutes les réponses ici sont excellentes mais, juste pour illustrer d'où cela vient, pour des questions comme celle-ci, il est bon d'aller à la source: la spécification de langage Java.

Section 15:23, Opérateur conditionnel-And (&&) , dit:

L'opérateur && ressemble à & (§15.22.2), mais il n'évalue son opérande de droite que si la valeur de son opérande de gauche est vraie. [...] Au moment de l'exécution, l'expression de l'opérande de gauche est évaluée en premier [...] si la valeur résultante est false, la valeur de l'expression conditionnelle et expression est false et l'expression de l'opérande de droite n'est pas évaluée. . Si la valeur de l'opérande de gauche est true, alors l'expression de droite est évaluée [...] et la valeur résultante devient la valeur de l'expression conditionnelle. Ainsi, && calcule le même résultat que & on des opérandes booléens. Il ne diffère que par le fait que l'expression de l'opérande de droite est évaluée conditionnellement plutôt que toujours.

Et de même, Section 15:24, opérateur Conditionnel-Or (||) , dit:

Le || opérateur est comme | (§15.22.2), mais n'évalue son opérande de droite que si la valeur de son opérande de gauche est false. [...] Au moment de l'exécution, l'expression de l'opérande gauche est évaluée en premier; [...] si la valeur résultante est true, la valeur de l'expression conditionnelle ou true est vraie et l'expression de l'opérande de droite n'est pas évaluée. Si la valeur de l'opérande de gauche est false, l'expression de droite est évaluée. [...] la valeur résultante devient la valeur de l'expression conditionnelle. Ainsi, || calcule le même résultat que | sur des opérandes booléens ou booléens. Il ne diffère que par le fait que l'expression de l'opérande de droite est évaluée conditionnellement plutôt que toujours.

Un peu répétitif, peut-être, mais la meilleure confirmation de la façon dont ils fonctionnent. De même, l'opérateur conditionnel (? :) n'évalue que la "moitié" appropriée (moitié gauche si la valeur est vraie, moitié droite si elle est fausse), permettant ainsi l'utilisation d'expressions telles que:

int x = (y == null) ? 0 : y.getFoo();

sans NullPointerException.

19
Cowan

Non, si a est vrai (dans un test or), b ne sera pas testé, car le résultat du test sera toujours vrai, quelle que soit la valeur de l'expression b.

Faites un test simple:

if (true || ((String) null).equals("foobar")) {
    ...
}

va pas lancer un NullPointerException!

6
Romain Linsolas

Court-circuit signifie ici que la deuxième condition ne sera pas évaluée.

Si (A && B) entraînera un court-circuit si A est Faux.

Si (A && B) va pas entraîner un court-circuit si A est vrai.

Si (A || B) entraînera un court-circuit si A est vrai.

Si (A || B) pas entraînera un court-circuit si A est faux.

5
user3211238

Oui, l'évaluation du court-circuit pour les expressions booléennes est le comportement par défaut de toute la famille C-like.

Un fait intéressant est que Java utilise également les opérandes logiques & et | (ils sont surchargés, avec les types int qu'ils sont attendus au niveau du bit) tous les termes de l'expression, ce qui est également utile lorsque vous avez besoin des effets secondaires.

4
fortran

Non, Java court-circuitera et arrêtera l'évaluation une fois le résultat obtenu.

4
abyx

Cela remonte à la différence fondamentale entre & et &&&, | et ||

BTW vous effectuez les mêmes tâches à plusieurs reprises. Pas sûr que l'efficacité soit un problème. Vous pouvez supprimer une partie de la duplication.

Z z2 = partialHits.get(req_nr).get(z); // assuming a value cannout be null.
Z z3 = tmpmap.get(z); // assuming z3 cannot be null.
if(z2 == null || z2 < z3){   
    partialHits.get(z).put(z, z3);   
} 
0
Peter Lawrey