Сокращенный оператор "или-назначения" (| =) в Java - PullRequest
81 голосов
/ 21 марта 2010

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

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

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


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

Ответы [ 8 ]

191 голосов
/ 21 марта 2010

|= является составным оператором присваивания ( JLS 15.26.2 ) для логического логического оператора | ( JLS 15.22.2 );не следует путать с условным или || ( JLS 15,24 ).Также есть &= и ^=, соответствующие версии составного назначения логического логического & и ^ соответственно.

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

 b1 |= b2;
 b1 = b1 | b2;

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

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

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

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

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

16 голосов
/ 21 марта 2010

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

В качестве примера различия, этот код будет в порядке, если text равно нулю:

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

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

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

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

3 голосов
/ 21 марта 2010

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

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

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

1 голос
/ 16 апреля 2018

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

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

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

Какой смысл в этом?Смысл состоял в том, чтобы избежать шаблонов и исключить повторяющийся код.

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

b1 |= b2;
1 голос
/ 25 апреля 2013

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

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

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

Edit: Еще большую читабельность можно достичь с помощью параметров varargs:

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

boolean checkIfAnyNegative(DataType ... data)

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

checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );
1 голос
/ 22 марта 2010

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

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

0 голосов
/ 11 января 2013

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

| = побитовое ИЛИ и оператор присваивания

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


C |= 2 is same as C = C | 2

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

0 голосов
/ 21 марта 2010
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale, 
                                       defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;
...