Почему мы обычно используем `||`, а не `|`, в чем разница? - PullRequest
207 голосов
/ 18 августа 2011

Мне просто интересно, почему мы обычно используем логическое ИЛИ || между двумя логическими значениями, а не побитовым ИЛИ |, хотя они оба работают хорошо.*

if(true  | true)  // pass
if(true  | false) // pass
if(false | true)  // pass
if(false | false) // no pass
if(true  || true)  // pass
if(true  || false) // pass
if(false || true)  // pass
if(false || false) // no pass

Можем ли мы использовать | вместо ||?То же самое с & и &&.

Ответы [ 27 ]

335 голосов
/ 18 августа 2011

Если вы используете формы || и &&, а не формы | и & этих операторов, Java не потрудится оценить только правый операнд.

Вопрос в том, хотите ли вы замкнуть оценку или нет - большую часть времени, которое вы хотите.

Хороший способ проиллюстрировать преимущества короткого замыкания - рассмотреть следующий пример.

Boolean b = true;
if(b || foo.timeConsumingCall())
{
   //we entered without calling timeConsumingCall()
}

Еще одно преимущество, как отмечали Джереми и Питер, для короткого замыкания - проверка нулевой ссылки:

if(string != null && string.isEmpty())
{
    //we check for string being null before calling isEmpty()
}

подробнее

80 голосов
/ 19 сентября 2008

| не выполняет оценку короткого замыкания в логических выражениях. || прекратит оценку, если первый операнд имеет значение true, но | - нет.

Кроме того, | может использоваться для выполнения операции побитового ИЛИ для значений байтов / коротких / целых / длинных. || не может.

64 голосов
/ 18 августа 2011

Так что просто для того, чтобы использовать другие ответы на примере, короткое замыкание имеет решающее значение в следующих защитных проверках:

if (foo == null || foo.isClosed()) {
    return;
}

if (bar != null && bar.isBlue()) {
    foo.doSomething();
}

Использование вместо | и & может привести к NullPointerException здесь бросают.

38 голосов
/ 18 августа 2011

Логические || и && проверяют только правую сторону при необходимости.| и & проверяют обе стороны каждый раз.

Например:

int i = 12;
if (i == 10 & i < 9) // It will check if i == 10 and if i < 9
...

Перепишите:

int i = 12;
if (i == 10 && i < 9) // It will check if i == 10 and stop checking afterward because i != 10
...

Другой пример:

int i = 12;
if (i == 12 | i > 10) // It will check if i == 12 and it will check if i > 10
...

Перепишите его:

int i = 12;
if (i == 12 || i > 10) // It will check if i == 12, it does, so it stops checking and executes what is in the if statement
...
17 голосов
/ 18 августа 2011

Также обратите внимание на распространенную ловушку: не ленивые операторы имеют приоритет над ленивыми, поэтому:

boolean a, b, c;
a || b && c; //resolves to a || (b && c)
a | b && c; //resolves to (a | b) && c

Будьте осторожны при их смешивании.

15 голосов
/ 18 августа 2011

В дополнение к короткому замыканию следует помнить, что выполнение побитовой логической операции со значениями, которые могут быть отличны от 0 или 1, имеет совершенно другое значение, чем условная логика. Хотя он ОБЫЧНО одинаков для | и ||, с & и && вы получите очень разные результаты (например, 2 & 4 равно 0 / false, а 2 && 4 равно 1 / true).

Если то, что вы получаете от функции, на самом деле является кодом ошибки, и вы проверяете не ноль, это может иметь большое значение.

Это не такая большая проблема в Java, где вам приходится явно вводить тип для логического значения или сравнивать с 0 и т. П., Но в других языках с похожим синтаксисом (C / C ++ и др.) Это может быть довольно запутанным.

Также обратите внимание, что & и | может применяться только к значениям целочисленного типа, а не ко всему, что может быть эквивалентно логическому тесту. Опять же, в не-Java языках есть довольно много вещей, которые можно использовать как логическое с неявным != 0 сравнением (указатели, числа с плавающей точкой, объекты с operator bool() и т. Д.), А побитовые операторы почти всегда бессмысленны в этих контекстах.

9 голосов
/ 18 августа 2011

Единственный раз, когда вы будете использовать | или & вместо || или &&, это когда у вас очень простые логические выражения, а стоимость короткой резки (т.е. ветви) больше, чем время сохранить, не оценив последующие выражения.

Однако это микрооптимизация, которая редко имеет значение, за исключением кода самого низкого уровня.

8 голосов
/ 19 сентября 2008

|| является логическим или оператором в то время как | является побитовым или оператором.

boolean a = true;
boolean b = false;

if (a || b) {
}

int a = 0x0001;
a = a | 0x0002;
8 голосов
/ 19 сентября 2008

а | b: оценить b в любом случае

a || b: оценивать b только если a равно false

7 голосов
/ 19 сентября 2008

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

 if(something || someotherthing)
 if(something | someotherthing)

если что-то ИСТИННО, || не буду ничего оценивать, пока | Сделаю. Если переменные в ваших операторах if на самом деле являются вызовами функций, используйте || возможно, сохранит много производительности.

...