Ярлык «или-присваивание» (| =) в Java

У меня есть длинный набор сравнений для Java, и я хотел бы знать, если один или несколько из них выдаются как истинные. Строка сравнений была длинной и трудной для чтения, поэтому я разбил ее на читаемость и автоматически пошел использовать оператор быстрого доступа |= а не negativeValue = negativeValue || boolean negativeValue = negativeValue || boolean .

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

Я ожидаю, что значение negativeValue будет истинным, если любые значения по умолчанию отрицательны. Действительно ли это? Будет ли это делать то, что я ожидаю? Я не мог видеть, что это упоминается на сайте Sun или stackoverflow, но Eclipse, похоже, не имеет с ним проблем, и код компилируется и запускается.


Точно так же, если бы я хотел выполнить несколько логических пересечений, могу ли я использовать &= вместо && ?

|= Представляет собой сложный оператор присваивания ( JLS 15.26.2 ) для логического логического оператора | ( JLS 15.22.2 ); не следует путать с условным или || ( JLS 15.24 ). Существуют также &= и ^= соответствующие версии составного назначения логических логических & и ^ соответственно.

Другими словами, для boolean b1, b2 эти два эквивалентны:

  b1 |= b2; b1 = b1 | b2; 

Разница между логическими операторами ( & и | ) по сравнению с их условными аналогами ( && и || ) заключается в том, что первые не являются «короткозамкнутыми»; последние делают. То есть:

  • & and | всегда оценивайте оба операнда
  • && и || оценивать правый операнд условно ; правый операнд оценивается только в том случае, если его значение может повлиять на результат двоичной операции. Это означает, что правый операнд НЕ оценивается, когда:
    • Левый операнд && оценивает значение false
      • (поскольку независимо от того, что оценивает правильный операнд, все выражение false )
    • Левый операнд || оценивается как true
      • (потому что независимо от того, что оценивает правильный операнд, все выражение true )

Итак, вернемся к вашему первоначальному вопросу, да, эта конструкция верна, а while |= не является эквивалентным ярлыком для = и || , он вычисляет то, что вы хотите. Поскольку правая часть оператора |= в вашем использовании является простой операцией сравнения целого числа, тот факт, что | не замыкается на короткое замыкание.

Бывают случаи, когда требуется короткое кодирование или даже требуется, но ваш сценарий не является одним из них.

К сожалению, в отличие от некоторых других языков, Java не имеет &&= и ||= . Это обсуждалось в вопросе Почему Java не имеет составных версий условных и условных операторов или операторов? (&& =, || =) .

Это не «короткий» (или короткозамкнутый) оператор в том смысле, что || и && (в этом они не будут оценивать RHS, если они уже знают результат на основе LHS), но он будет делать то, что вы хотите с точки зрения работы .

В качестве примера разницы этот код будет хорош, если text имеет значение null:

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

тогда как это не будет:

 boolean nullOrEmpty = false; nullOrEmpty |= text == null; nullOrEmpty |= text.equals(""); // Throws exception if text is null 

(Очевидно, вы могли бы сделать "".equals(text) для этого конкретного случая – я просто пытаюсь продемонстрировать принцип.)

У вас может быть только одно заявление. Выраженный над несколькими строками, он читается почти так же, как и ваш пример кода, только менее важно:

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

Для простейших выражений, используя | может быть быстрее, чем || потому что, несмотря на то, что он избегает выполнения сравнения, это подразумевает использование ветви неявно и может быть во много раз дороже.

Хотя это может быть излишним для вашей проблемы, библиотека Guava имеет хороший синтаксис с Predicate s и делает короткую проверку или / или Predicate s.

По сути, сравнения превращаются в объекты, упакованные в коллекцию и затем повторяющиеся. Для или предикатов первое истинное попадание возвращается с итерации, и наоборот для и.

Если речь идет о удобочитаемости, то я получил концепцию данных, связанных с разделением, из логики тестирования. Пример кода:

 // 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; } 

Код выглядит более подробным и самоочевидным. Вы даже можете создать массив в вызове метода, например:

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

Это более читаемо, чем «строка сравнения», а также имеет преимущество в производительности короткого замыкания (за счет распределения массива и вызова метода).

Изменить: еще более читаемость может быть достигнута с помощью параметров varargs:

Подпись метода:

 boolean checkIfAnyNegative(DataType ... data) 

И вызов мог бы выглядеть так:

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

|| логическое логическое ИЛИ
| побитовое ИЛИ

| = побитовое включение OR и оператор присваивания

Причина, по которой | = не shortcircit, состоит в том, что она выполняет побитовое ИЛИ не логическое ИЛИ. То есть:

 C | = 2 совпадает с C = C |  2

Учебник для операторов Java

Это старая должность, но для того, чтобы представить себе новую перспективу для новичков, я хотел бы привести пример.

Я думаю, что наиболее распространенным вариантом использования подобного сложного оператора будет += . Я уверен, что все мы писали что-то вроде этого:

 int a = 10; // a = 10 a += 5; // a = 15 

В чем смысл этого? Это должно было не записывать переменную дважды в одну строку. (Я пропустил что-то превосходное здесь?)

Итак, следующая строка делает то же самое, избегая вводить переменную b1 дважды в одну строку.

 b1 |= b2; 
Давайте будем гением компьютера.