Оператор быстрого доступа "or-assignment" ( | = ) в Java
у меня есть длинный набор сравнений сделать в Java, и я хотел бы знать, если один или несколько из них вышли как истинные. Строка сравнений была длинной и трудной для чтения, поэтому я разбил ее для удобства чтения и автоматически пошел использовать оператор быстрого доступа |=, а не negativeValue = negativeValue || boolean.
boolean negativeValue = false;
negativeValue |= (defaultStock < 0);
negativeValue |= (defaultWholesale < 0);
negativeValue |= (defaultRetail < 0);
negativeValue |= (defaultDelivery < 0);
Я жду negativeValue значение true, если любое из значений по умолчанию является отрицательным. Это действительно так? Будет ли он делать то, что я ожидаю? Я не мог видеть, что это упоминается на сайте Sun или stackoverflow, но Eclipse, похоже, не имеет проблем с ним, и код компилируется и запускается.
аналогично, если бы я хотел выполнить несколько логических пересечений, я мог бы использовать &= вместо &&?
8 ответов:
The
|=является составным оператором присваивания (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 не имеет составных версий присваивания операторов условного и и условного или? (&&=, ||=).
это не" ярлык " (или короткое замыкание) оператор таким образом, что | / и && являются (в том, что они не будут оценивать 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;для простейших выражений, используя
|может быть быстрее, чем||потому что даже если он избегает делать сравнение, это означает неявное использование ветви, и это может быть во много раз дороже.
хотя это может быть излишним для вашей проблемы,гуавы библиотека имеет хороший синтаксис с
Predicates и делает оценку короткого замыкания или / иPredicates.по существу, сравнения превращаются в объекты, упаковываются в коллекцию, а затем повторяются. Для предикатов 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;
Comments