web-dev-qa-db-fra.com

Raccourci "ou -affectation" (| =) opérateur en Java

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 &&?

79
David Mason

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:
    • L'opérande gauche de && correspond à false
      • (car peu importe ce que l'opérande correct évalue, l'expression entière est false)
    • L'opérande gauche de || correspond à true
      • (car peu importe l'opérande correct, l'expression entière est 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? (&& =, || =).

188
polygenelubricants

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.)

16
Jon Skeet

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.

3
Peter Lawrey

Bien que votre problème puisse sembler excessif, la bibliothèque Guava a une syntaxe de Nice avec Predicates et effectue une évaluation en court-circuit de ou/et Predicates.

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.

1
Carl

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 );
1

|| 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 

Tutoriel pour opérateurs Java

0
oneklc

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;
0
oxyt
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale, 
                                       defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;
0
Roman