web-dev-qa-db-fra.com

Pourquoi Java n'a-t-il pas de version d'assignation composée des opérateurs conditionnel et et conditionnel ou? (&& =, || =)

Donc, pour les opérateurs binaires sur les booléens, Java a &, |, ^, && et ||.

Résumons ce qu'ils font brièvement ici:

Pour &, la valeur du résultat est true si les deux valeurs d'opérande sont true; sinon, le résultat est false.

Pour |, la valeur du résultat est false si les deux valeurs d'opérande sont false; sinon, le résultat est true.

Pour ^, la valeur du résultat est true si les valeurs d'opérande sont différentes; sinon, le résultat est false.

L'opérateur && ressemble à & mais n'évalue son opérande de droite que si la valeur de son opérande de gauche est true.

L'opérateur || ressemble à |, mais n'évalue son opérande de droite que si la valeur de son opérande de gauche est false.

Maintenant, parmi les 5, 3 d'entre eux ont des versions d'assignation composées, à savoir |=, &= et ^=. Ma question est donc évidente: pourquoi Java ne fournit-il pas également &&= et ||=? Je trouve que j'ai besoin de ceux-ci plus que j'ai besoin de &= et |=.

Et je ne pense pas que "parce que c'est trop long" soit une bonne réponse, car Java a >>>=. Il doit y avoir une meilleure raison pour cette omission.


De 15.26 Opérateurs d’affectation :

Il y a 12 opérateurs d'affectation; [...] = *= /= %= += -= <<= >>= >>>= &= ^= |=


Un commentaire a été fait sur le fait que si &&= et ||= étaient implémentés, ce seraient les seuls opérateurs qui n'évaluaient pas le côté droit en premier. Je pense que l'idée qu'un opérateur d'assignation composé évalue le côté droit en premier est une erreur.

De 15.26.2 Opérateurs d’assignation composée :

Une expression d'affectation composée de la forme E1 op= E2 équivaut à E1 = (T)((E1) op (E2)), où T est le type de E1, sauf que E1 n'est évalué qu'une fois. 

Pour preuve, l'extrait suivant lance une NullPointerException, pas une ArrayIndexOutOfBoundsException.

    int[] a = null;
    int[] b = {};
    a[0] += b[-1];
72
polygenelubricants

Raison

Les opérateurs &&= et ||= ne sont pas disponibles sur Java car pour la plupart des développeurs, ces opérateurs sont:

  • sujet aux erreurs
  • inutile

Exemple pour &&=

Si Java autorise l'opérateur &&=, alors ce code:

bool isOk = true; //becomes false when at least a function returns false
isOK &&= f1();
isOK &&= f2(); //we may expect f2() is called whatever the f1() returned value

serait équivalent à:

bool isOk = true;
if (isOK) isOk = f1();
if (isOK) isOk = f2(); //f2() is called only when f1() returns true

Ce premier code est sujet aux erreurs car de nombreux développeurs pensent que f2() est toujours appelé, quelle que soit la valeur renvoyée par f1 (). Cela ressemble à bool isOk = f1() && f2();f2() est appelé uniquement lorsque f1() renvoie true

Si le développeur souhaite que f2() ne soit appelé que lorsque f1() renvoie true, le second code ci-dessus est donc moins sujet aux erreurs.

Sinon &= est suffisant car le développeur souhaite que f2() soit toujours appelé:

Même exemple mais pour &=

bool isOk = true;
isOK &= f1();
isOK &= f2(); //f2() always called whatever the f1() returned value

De plus, la machine virtuelle Java doit exécuter le code ci-dessus comme suit:

bool isOk = true;
if (!f1())  isOk = false;
if (!f2())  isOk = false;  //f2() always called

Comparer les résultats && et &

Les résultats des opérateurs && et & sont-ils les mêmes lorsqu'ils sont appliqués à des valeurs booléennes?

Vérifions en utilisant le code Java suivant:

public class qalcdo {

    public static void main (String[] args) {
        test (true,  true);
        test (true,  false);
        test (false, false);
        test (false, true);
    }

    private static void test (boolean a, boolean b) {
        System.out.println (counter++ +  ") a=" + a + " and b=" + b);
        System.out.println ("a && b = " + (a && b));
        System.out.println ("a & b = "  + (a & b));
        System.out.println ("======================");
    }

    private static int counter = 1;
}

Sortie:

1) a=true and b=true
a && b = true
a & b = true
======================
2) a=true and b=false
a && b = false
a & b = false
======================
3) a=false and b=false
a && b = false
a & b = false
======================
4) a=false and b=true
a && b = false
a & b = false
======================

Par conséquentOUInous pouvons remplacer && par & pour les valeurs booléennes ;-) 

Il vaut donc mieux utiliser &= au lieu de &&=.

Idem pour ||=

Mêmes raisons que pour &&=
L'opérateur |= est moins sujet aux erreurs que ||=.

Si un développeur souhaite que f2() ne soit pas appelé lorsque f1() renvoie true, je conseille les alternatives suivantes:

// here a comment is required to explain that 
// f2() is not called when f1() returns false, and so on...
bool isOk = f1() || f2() || f3() || f4();

ou:

// here the following comments are not required 
// (the code is enough understandable)
bool isOk = false;
if (!isOK) isOk = f1();
if (!isOK) isOk = f2(); //f2() is not called when f1() returns false
if (!isOK) isOk = f3(); //f3() is not called when f1() or f2() return false
if (!isOK) isOk = f4(); //f4() is not called when ...
23
olibre

Probablement parce que quelque chose comme

x = false;
x &&= someComplexExpression();

semble comme si cela devait assigner x et évaluer someComplexExpression(), mais le fait que l'évaluation repose sur la valeur de x n'apparaît pas dans la syntaxe.

De plus, la syntaxe de Java étant basée sur le C, personne n’a jugé urgent d’ajouter ces opérateurs. De toute façon, vous seriez probablement mieux avec une déclaration if.

16
Josh Lee

C'est comme ça en Java, parce que c'est comme ça en C.

Maintenant, la question de savoir pourquoi il en est ainsi dans C est que lorsque & & && sont devenus des opérateurs différents (parfois avant que C ne descende de B), la variété d'opérateurs & = a tout simplement été négligée.

Mais la deuxième partie de ma réponse ne dispose d'aucune source pour la sauvegarder.

8
EFraim

En grande partie parce que la syntaxe Java est basée sur C (ou au moins la famille C), et qu'en C, tous ces opérateurs d'affectation sont compilés en instructions arithmétiques ou assemblées au niveau du bit sur un seul registre. La version affectation-opérateur évite les temporaires et peut avoir produit un code plus efficace sur les premiers compilateurs non optimiseurs. Les équivalents d'opérateur logique (comme ils sont appelés en C) (&&= et ||=) n'ont pas une correspondance aussi évidente avec les instructions d'assemblage simples; ils se développent généralement en une séquence d'instructions de test et de branchement.

Fait intéressant, des langues comme Ruby do ont || = et && =.

Edit: la terminologie diffère entre Java et C

4
p00ya

L'un des objectifs originaux de Java devait être «simple, orienté objet et familier». Appliqué dans ce cas, & = est familier (C, C++ et familier dans ce contexte signifiait familier à quelqu'un qui connaît ces deux).

&& = ne serait pas familier, et ce ne serait pas simple, en ce sens que les concepteurs de langage ne cherchaient pas à penser à tous les opérateurs qu’ils pourraient ajouter au langage, de sorte que moins d’opérateurs supplémentaires sont plus simples.

4
Yishai

Pour les vars booléens, && et || utiliserait l'évaluation de court-circuit tandis que & et | n’attendez donc pas que && = et || = utilisent également l’évaluation des courts-circuits. Il y a un bon cas d'utilisation pour cela. Surtout si vous parcourez une boucle, vous voulez être rapide, efficace et concis. 

Au lieu d'écrire 

foreach(item in coll)
{
   bVal = bVal || fn(item); // not so elegant
}

Je veux ecrire

foreach(item in coll)
{
  bVal ||= fn(item);    // elegant
}

et sachez qu'une fois que bVal est vrai, fn () ne sera pas appelé pour le reste des itérations.

3
zanfilip

'&' et '&&' sont différents de '&&' est une opération de raccourci qui ne fonctionnera pas si le premier opérande est faux alors que '&' le fera quand même (fonctionne à la fois avec nombre et booléen).

Je conviens qu'il est plus logique d'exister, mais ce n'est pas si grave si ce n'est pas là. Je suppose que ce n'était pas là parce que C ne l'a pas.

Je ne vois vraiment pas pourquoi.

2
NawaMan

C'est permis en Ruby. 

Si je devais deviner, je dirais que ce n'est pas fréquemment utilisé alors il n'a pas été mis en œuvre. Une autre explication pourrait être que l’analyseur ne regarde que le caractère avant le = 

0
zzawaideh

a & b et a && b ne sont pas la même chose.

a && b est une expression booléenne qui renvoie un booléen, et a & b est une expression au niveau des bits qui renvoie un entier (si a et b sont des ints).

whare pensez-vous qu'ils sont les mêmes?

0
Omry Yadan

Je ne peux pas penser à une meilleure raison alors 'C'est incroyable, c'est moche!'

0
Daniel Brückner

Et

vérifie les deux opérandes, c’est un opérateur au niveau des bits. Java définit plusieurs opérateurs au niveau des bits, qui peuvent être appliqués aux types entiers, long, int, short, char et byte.

&&

arrête d’évaluer si le premier opérande a la valeur false car le résultat sera false, c’est un opérateur logique. Il peut être appliqué aux booléens.

L'opérateur && est similaire à l'opérateur &, mais peut rendre votre code un peu plus efficace. Comme les deux expressions comparées par l’opérateur & doivent être vraies pour que toute l’expression soit vraie, il n’ya aucune raison d’évaluer la deuxième expression si la première renvoie faux. L'opérateur & évalue toujours les deux expressions. L'opérateur && n'évalue la deuxième expression que si la première est vraie.

Avoir un opérateur d'affectation && = n'ajouterait pas vraiment de nouvelles fonctionnalités à la langue. L'arithmétique de l'opérateur au niveau du bit est beaucoup plus expressive, vous pouvez utiliser l'arithmétique au niveau du bit entier, qui inclut l'arithmétique booléenne. Les opérateurs logiques peuvent simplement faire de l'arithmétique booléenne.

0
Ely