Opérateur de raccourci «ou-affectation» (| =) en Java

J’ai une longue série de comparaisons à faire en Java et j’aimerais savoir si un ou plusieurs d’entre eux sont vrais. La chaîne de comparaisons était longue et difficile à lire, donc je l’ai brisée pour la lisibilité, et j’ai automatiquement utilisé un opérateur de raccourci |= plutôt que negativeValue = negativeValue || boolean negativeValue = negativeValue || boolean

 boolean negativeValue = false; negativeValue |= (defaultStock < 0); negativeValue |= (defaultWholesale < 0); negativeValue |= (defaultRetail < 0); negativeValue |= (defaultDelivery < 0); 

Je pense que negativeValue est vrai si l’une des valeurs par défaut est négative. Est-ce que c’est valide? Va-t-il faire 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 et le code est compilé et exécuté.


De même, si je voulais effectuer plusieurs intersections logiques, pourrais-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 y a aussi &= et ^= correspondant à la version d’affectation composée des booléens logiques & 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 | ) et leurs contreparties conditionnelles ( && et || ) est que les premiers ne «court-circuitent pas»; les derniers font. C’est:

  • & et | toujours évaluer les deux opérandes
  • && et || évaluer le bon opérande conditionnellement ; l’opérande droit n’est évalué que si sa valeur peut affecter le résultat de l’opération binary. Cela signifie que le bon opérande n’est PAS évalué lorsque:
    • L’opérande gauche de && évalué à false
      • (parce que peu importe l’opérande qui est évalué, l’expression entière est false )
    • L’opérande gauche de || évalue à true
      • (parce que peu importe le bon opérande évalué, l’expression entière est true )

Donc, revenons à votre question initiale, oui, cette construction est valide, et tant que |= n’est 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-circuit pas est insignifiant.

Il y a des cas où le court-circuit est souhaité, ou même requirejs, mais votre scénario n’en fait pas partie.

Il est regrettable que, contrairement à d’autres langages, Java n’ait pas &&= et ||= . Cela a été discuté dans la question Pourquoi Java ne dispose-t-il pas de versions d’affectation composée des opérateurs conditionnels et / ou conditionnels ou? (&& =, || =) .

Ce n’est pas un opérateur “raccourci” (ou court-circuité) de la manière suivante: || et && sont (en ce sens qu’ils n’évalueront pas le RHS s’ils connaissent déjà le résultat basé sur le LHS), mais ils feront ce que vous voulez en termes de fonctionnement .

Comme exemple de la différence, ce code sera correct si le text est nul:

 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 pourriez faire "".equals(text) pour ce cas particulier – j’essaie juste de démontrer le principe.)

Vous pourriez juste avoir 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, utilisez | peut être plus rapide que || car même si cela évite de faire une comparaison, cela signifie implicitement utiliser une succursale et cela peut coûter beaucoup plus cher.

Bien que cela puisse sembler exagéré pour votre problème, la bibliothèque Guava a une belle syntaxe avec Predicate s et effectue une évaluation en court-circuit de ou / et des Predicate .

Essentiellement, les comparaisons sont transformées en objects, regroupées dans une collection, puis répétées. Pour ou prédicats, le premier hit réel retourne de l’itération et vice versa pour et.

En ce qui concerne la lisibilité, le concept de séparation des données testées de la logique de test. Échantillon 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 semble plus verbeux et explicite. Vous pouvez même créer un tableau dans l'appel de méthode, comme ceci:

 checkIfAnyNegative(new DataType[] { defaultStock, defaultWholesale, defaultRetail, defaultDelivery }); 

Il est plus lisible que la «chaîne de comparaison» et présente également un avantage en termes de performances en termes de court-circuit (au désortingment de l'allocation de masortingce et de l'appel de méthode).

Edit: Encore plus de lisibilité peut être obtenue simplement en utilisant les parameters varargs:

La signature de la méthode serait:

 boolean checkIfAnyNegative(DataType ... data) 

Et l'appel pourrait ressembler à ceci:

 checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery ); 
 List params = Arrays.asList (defaultStock, defaultWholesale, defaultRetail, defaultDelivery); int minParam = Collections.min (params); negativeValue = minParam < 0; 

|| booléen logique OU
| bit à bit OU

| = Opérateur ou opérateur d’affectation inclusivement

La raison pour laquelle | = ne court-circuite pas est qu’il fait un OU au niveau du bit et non un OU logique. C’est-à-dire:


 C | = 2 est identique à C = C |  2

Tutoriel pour les opérateurs Java

C’est un ancien message, mais pour donner une perspective différente 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 cela? 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?)

Donc, la ligne suivante fait exactement la même chose, évitant de taper la variable b1 deux fois dans la même ligne.

 b1 |= b2;