93 votes

Le raccourci "ou de cession" (|=) opérateur en Java

J'ai une longue série de comparaisons à faire en Java, et j'aimerais savoir si l'un ou plusieurs d'entre eux reviennent en vrai. La chaîne de comparaisons a été long et difficile à lire, donc je l'ai cassé pour des raisons de lisibilité, et automatiquement pour utiliser un raccourci de l'opérateur |= plutôt que d' negativeValue = negativeValue || boolean.

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

J'attends negativeValue vrai si tout de la valeur par défaut<quelque chose> les valeurs sont négatives. Est-ce valable? Faut-il faire ce que j'attends? Je ne vois pas mentionné sur les Chaises du site ou stackoverflow, mais Eclipse ne semble pas avoir un problème avec ça et le code compile et s'exécute.


De même, si je voulais effectuer plusieurs logiques intersections, pourrais-je l'utiliser &= au lieu de &&?

211voto

polygenelubricants Points 136838

L' |= est un composé que l'opérateur d'affectation (JLS 15.26.2) pour l'opérateur logique booléenne | (JLS 15.22.2); à ne pas confondre avec le conditionnel ou || (JLS 15.24). Il y a aussi &= et ^= correspondant au composé d'attribution de la version de la logique booléenne & et ^ respectivement.

En d'autres termes, pour boolean b1, b2, ces deux sont équivalentes:

 b1 |= b2;
 b1 = b1 | b2;

La différence entre les opérateurs logiques (& et |) par rapport à leur mise homologues (&& et ||), c'est que les anciens ne sont pas "court-circuit"; les seconds. C'est:

  • & et | toujours évaluer les deux opérandes
  • && et || évaluer l'opérande de droite conditionnellement; l'opérande de droite est évaluée uniquement si sa valeur pourrait affecter le résultat de l'opération binaire. Cela signifie que l'opérande de droite n'est PAS évaluée lors:
    • L'opérande gauche de l' && évalue false
      • (parce que peu importe ce que l'opérande de droite donne, l'expression entière est false)
    • L'opérande gauche de l' || évalue true
      • (parce que peu importe ce que l'opérande de droite donne, l'expression entière est true)

Pour en revenir à votre question initiale, oui, cette construction est valide, et bien |= n'est pas exactement l'équivalent de raccourci pour = et ||, il ne calculer ce que vous voulez. Depuis le côté droit de l' |= de l'opérateur de votre utilisation est un nombre entier simple opération de comparaison, le fait qu' | n'a pas de court-circuit est négligeable.

Il y a des cas, quand un court-circuit est souhaitée, ou même nécessaire, mais le scénario n'est pas l'un d'eux.

Il est regrettable que, contrairement à d'autres langages, Java ne dispose pas d' &&= et ||=. Cela a été abordé dans la question Pourquoi ne pas Java ont composé affectation versions du conditionnel et et conditionnel ou opérateurs? (&&=, ||=).

16voto

Jon Skeet Points 692016

Ce n'est pas un "raccourci" (ou court-circuit) de l'opérateur dans la façon dont les || et && sont (en ce qu'ils n'évalue pas le membre de droite s'ils connaissent déjà le résultat basé sur le LHS), mais il va faire ce que vous voulez en termes de travail.

Comme un exemple de la différence, ce code sera très bien si text est nulle:

boolean nullOrEmpty = text == null || text.equals("")

alors que ce ne sera 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, je suis juste essayer d'illustrer le principe.)

3voto

Peter Lawrey Points 229686

Peut-être vous avez une déclaration. Exprimé sur plusieurs lignes, il lit presque exactement comme votre exemple de code, seulement moins impératif:

boolean negativeValue
    = defaultStock < 0 
    | defaultWholesale < 0
    | defaultRetail < 0
    | defaultDelivery < 0;

Pour l'expression la plus simple, à l'aide de | peut être plus rapide que l' || parce que même si elle évite de faire une comparaison, il signifie à l'aide d'une branche implicitement et qui peut être beaucoup plus cher.

1voto

Carl Points 4049

Mais il serait peut-être exagéré pour votre problème, la Goyave, la bibliothèque a quelques belles syntaxe, Predicates et n'évaluation de court-circuit ou/et Predicates.

Essentiellement, les comparaisons sont transformés en objets, sous la forme d'une collection, puis itéré. Pour ou prédicats, le premier vrai coup de retour de l'itération, et vice versa pour et.

1voto

Si c'est à propos de la lisibilité j'ai le concept de la séparation de données testé à partir de l'essai de logique. 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 est plus détaillé et auto-explicatif. Vous pouvez même créer un tableau dans l'appel de la méthode, comme ceci:

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

C'est plus lisible que la "comparaison de chaîne", et a également l'avantage de performance de court-circuit (le coût de l'allocation de tableau et de l'appel de méthode).

Edit: Même plus de lisibilité peut être obtenu simplement en utilisant varargs paramètres:

Signature de la méthode serait:

boolean checkIfAnyNegative(DataType ... data)

Et l'appel pourrait ressembler à ceci:

checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X