Ярлык" or-assignment " ( | = ) оператор в Java
у меня есть длинный набор сравнений на Java, и я хотел бы знать, если один или несколько из них выходят как правда. Строка сравнений была длинной и трудной для чтения, поэтому я разбил ее на удобочитаемость и автоматически пошел использовать оператор shortcut |=
, а не negativeValue = negativeValue || boolean
.
boolean negativeValue = false;
negativeValue |= (defaultStock < 0);
negativeValue |= (defaultWholesale < 0);
negativeValue |= (defaultRetail < 0);
negativeValue |= (defaultDelivery < 0);
Я жду negativeValue
значение true, если любое из значений по умолчанию отрицательно. Это действительно так? Будет ли он делать то, что я ожидаю? Я не видел, чтобы это упоминалось на сайте Sun или stackoverflow, но Eclipse, похоже, не имеет проблем с ним, и код компилируется и запускается.
аналогично, если бы я хотел выполнить несколько логических пересечений, я мог бы использовать &=
вместо &&
?
8 ответов
на |=
является составным оператором присваивания (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 не имеет составных версий назначения условных и и условных операторов or? (&&=, ||=).
это не" ярлык " (или короткое замыкание) оператор таким образом, что || и & & (в том, что они не будут оценивать 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;
для простейших выражений, используя |
может быть быстрее, чем ||
потому что даже если он избегает сравнения, это означает использование ветви неявно, и это может быть во много раз дороже.
хотя это может быть излишним для вашей проблемы,гуавы библиотека имеет хороший синтаксис с Predicate
s и делает оценку короткого замыкания or / and Predicate
s.
по сути, сравнения превращаются в объекты, упаковываются в коллекцию,а затем повторяются. Для предикатов or первый истинный удар возвращается с итерации, и наоборот для and.
если речь идет о читаемости, у меня есть концепция разделения проверенных данных из логики тестирования. Пример кода:
// 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 );
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale,
defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;
|| логическое логическое или
/ побитовое или
/ = побитовое включительно или и оператор присваивания
почему |= не shortcircit потому, что он делает побитовое или логическое или. То есть:
C |= 2 is same as C = C | 2
Это старый пост, но для того, чтобы обеспечить другую перспективу для начинающих, я хотел бы привести пример.
Я думаю, что наиболее распространенным вариантом использования для аналогичного составного оператора будет +=
. Я уверен, что мы все написали что-то вроде этого:
int a = 10; // a = 10
a += 5; // a = 15
какой в этом был смысл? Это было, чтобы избежать написания переменной a
дважды в одной строке. (Не упускаю ли я чего-то высшего?)
Итак, следующая строка делает то же самое, избегая введите переменную b1
дважды в одной строке.
b1 |= b2;