J'ai une longue série de comparaisons à faire en Java et j'aimerais savoir si une ou plusieurs d'entre elles sont vraies. La chaîne de comparaisons était longue et difficile à lire, je l'ai donc divisée pour une meilleure lisibilité et suis automatiquement passée à un opérateur de raccourci |=
plutôt que negativeValue = negativeValue || boolean
.
boolean negativeValue = false;
negativeValue |= (defaultStock < 0);
negativeValue |= (defaultWholesale < 0);
negativeValue |= (defaultRetail < 0);
negativeValue |= (defaultDelivery < 0);
Je pense que negativeValue
sera vrai si l'une des valeurs par défaut <quelque chose> est négative. Est-ce valide? Fera-t-il ce que j'attends? Je ne pouvais pas le voir mentionné sur le site ou le stackoverflow de Sun, mais Eclipse ne semble pas avoir de problème avec cela et le code est compilé et exécuté.
De même, si je souhaitais effectuer plusieurs intersections logiques, puis-je utiliser &=
au lieu de &&
?
Le |=
est un opérateur d'assignation composé ( JLS 15.26.2 ) pour l'opérateur logique booléen |
( JLS 15.22.2 ); à ne pas confondre avec le conditionnel- ou ||
( JLS 15.24 ). Il existe également &=
et ^=
correspondant à la version d'assignation composée du booléen logique &
et ^
respectivement.
En d'autres termes, pour boolean b1, b2
, ces deux sont équivalents:
b1 |= b2;
b1 = b1 | b2;
La différence entre les opérateurs logiques (&
et |
) par rapport à leurs équivalents conditionnels (&&
et ||
) est que les premiers ne font pas de "court-circuit"; les derniers font. C'est:
&
et |
always évaluent les deux opérandes&&
et ||
évaluent l'opérande de droite conditionally; l'opérande de droite n'est évalué que si sa valeur peut affecter le résultat de l'opération binaire. Cela signifie que l'opérande de droite n'est PAS évalué lorsque: &&
correspond à false
false
)||
correspond à true
true
)Donc, pour revenir à votre question initiale, oui, cette construction est valide, et bien que |=
ne soit pas exactement un raccourci équivalent pour =
et ||
, il calcule ce que vous voulez. Puisque le côté droit de l'opérateur |=
dans votre utilisation est une simple opération de comparaison d'entiers, le fait que |
ne court-circuite pas est insignifiant.
Il existe des cas dans lesquels un court-circuit est souhaité, voire requis, mais votre scénario n'en fait pas partie.
Il est regrettable que, contrairement à d’autres langues, Java n’ait pas &&=
et ||=
. Ceci a été discuté dans la question Pourquoi Java n’a-t-il pas de version d’affectation composée des opérateurs conditionnel et et conditionnel ou? (&& =, || =).
Ce n'est pas un opérateur de "raccourci" (ou de court-circuitage) de la manière || et && (en ce sens qu'ils n'évaluent pas l'ERS s'ils connaissent déjà le résultat basé sur l'ELS) mais ils feront ce que vous voulez en termes de travail .
Comme exemple de différence, ce code ira bien si text
est null:
boolean nullOrEmpty = text == null || text.equals("")
alors que cela ne va pas:
boolean nullOrEmpty = false;
nullOrEmpty |= text == null;
nullOrEmpty |= text.equals(""); // Throws exception if text is null
(Évidemment, vous pouvez faire "".equals(text)
pour ce cas particulier - j'essaie simplement de démontrer le principe.)
Vous pouvez avoir juste une déclaration. Exprimé sur plusieurs lignes, il se lit presque exactement comme votre exemple de code, mais moins impératif:
boolean negativeValue
= defaultStock < 0
| defaultWholesale < 0
| defaultRetail < 0
| defaultDelivery < 0;
Pour les expressions les plus simples, utiliser |
peut être plus rapide que ||
, car même si cela évite de faire une comparaison, cela signifie que vous utilisez implicitement une branche, ce qui peut coûter beaucoup plus cher.
Bien que votre problème puisse sembler excessif, la bibliothèque Guava a une syntaxe de Nice avec Predicate
s et effectue une évaluation en court-circuit de ou/et Predicate
s.
Essentiellement, les comparaisons sont transformées en objets, regroupées dans une collection, puis itérées. Pour ou prédicats, le premier véritable hit revient de l'itération, et inversement pour et.
S'il s'agit de lisibilité, j'ai le concept de séparation des données testées de la logique de test. Exemple de code:
// declare data
DataType [] dataToTest = new DataType[] {
defaultStock,
defaultWholesale,
defaultRetail,
defaultDelivery
}
// define logic
boolean checkIfAnyNegative(DataType [] data) {
boolean negativeValue = false;
int i = 0;
while (!negativeValue && i < data.length) {
negativeValue = data[i++] < 0;
}
return negativeValue;
}
Le code a l'air plus bavard et explicite. Vous pouvez même créer un tableau dans un appel de méthode, comme ceci:
checkIfAnyNegative(new DataType[] {
defaultStock,
defaultWholesale,
defaultRetail,
defaultDelivery
});
Il est plus lisible que 'chaîne de comparaison' et présente l'avantage du court-circuit sur les performances (au détriment de l'allocation de matrice et de l'appel de méthode).
Edit: Encore plus de lisibilité peut être obtenue simplement avec les paramètres varargs:
La signature de la méthode serait:
boolean checkIfAnyNegative(DataType ... data)
Et l'appel pourrait ressembler à ceci:
checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );
|| booléen logique OR
bitwise OU
| = bitwise OR et opérateur d'assignation
La raison pour laquelle | = ne court-circuite pas, c'est parce qu'il fait un bitwise OR pas un OU logique. C'est-à-dire:
C | = 2 est identique à C = C | 2
C'est un vieux post, mais pour donner un point de vue différent aux débutants, j'aimerais donner un exemple.
Je pense que le cas d'utilisation le plus courant pour un opérateur composé similaire serait +=
. Je suis sûr que nous avons tous écrit quelque chose comme ceci:
int a = 10; // a = 10
a += 5; // a = 15
Quel était le but de ceci? C'était pour éviter d'écrire la variable a
deux fois dans la même ligne. (Est-ce que je manque quelque chose de supérieur ici?)
Ainsi, la ligne suivante fait exactement la même chose, en évitant de taper deux fois la variable b1
dans la même ligne.
b1 |= b2;
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale,
defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;