Различия в логических операторах: & vs && и | vs ||

Ответы:

134

Это побитовые операторы И и ИЛИ.

int a = 6; // 110
int b = 4; // 100

// Bitwise AND    

int c = a & b;
//   110
// & 100
// -----
//   100

// Bitwise OR

int d = a | b;
//   110
// | 100
// -----
//   110

System.out.println(c); // 4
System.out.println(d); // 6

Спасибо Карлосу за указание на соответствующий раздел в спецификации языка Java ( 15.22.1 , 15.22.2 ), касающийся различного поведения оператора в зависимости от его входных данных.

Действительно, когда оба входа являются логическими, операторы считаются логическими логическими операторами и ведут себя аналогично операторам Conditional-And ( &&) и Conditional-Or ( ||), за исключением того факта, что они не замыкаются, поэтому следующее безопасно :

if((a != null) && (a.something == 3)){
}

Это не:

if((a != null) & (a.something == 3)){
}

«Короткое замыкание» означает, что оператор не обязательно проверяет все условия. В приведенных выше примерах, &&рассмотрим второе условие только тогда , когда aнет null( в противном случае весь оператор вернет ложь, и было бы спорно рассмотреть следующие условия в любом случае), поэтому утверждение a.somethingне вызывает исключение, или считается «безопасным . "

&Оператор всегда рассматривает все условия в предложении, так и в приведенных выше примерах, a.somethingможет быть оценен , когда aна самом деле nullзначение, вызывая исключение.

Джастин Нисснер
источник
1
хотел уточнить .. & вернет 1, только если ОБА 1? Значит, 101 & 001 будет 001? Правильно?
gideon
@giddy @Jonathon - Я обновил свои значения, чтобы лучше показать эту ситуацию.
Джастин Нисснер
неполный: они также являются ЛОГИЧЕСКИМИ операторами (для логических).
user85421
1
@ Карлос: Нет. Они по-прежнему побитовые операторы. Они просто ведут себя так же, как логические операторы без короткого замыкания. Есть разница.
Джастин Нисснер
4
и что такое логические операторы без короткого замыкания? Операторы & и | (по запросу OP) «Целочисленные побитовые операторы» (JLS 15.22.1) и «Булевы логические операторы» (JLS 15.22.2). Или это неверно в спецификации языка Java?
user85421
108

Я думаю, вы говорите о логическом значении обоих операторов, вот вам таблица-резюме:

boolean a, b;

Operation     Meaning                       Note
---------     -------                       ----
   a && b     logical AND                    short-circuiting
   a || b     logical OR                     short-circuiting
   a &  b     boolean logical AND            not short-circuiting
   a |  b     boolean logical OR             not short-circuiting
   a ^  b     boolean logical exclusive OR
  !a          logical NOT

short-circuiting        (x != 0) && (1/x > 1)   SAFE
not short-circuiting    (x != 0) &  (1/x > 1)   NOT SAFE

Оценка короткого замыкания , минимальная оценка или оценка Маккарти (после Джона Маккарти) - это семантика некоторых булевых операторов в некоторых языках программирования, в которых второй аргумент выполняется или оценивается только в том случае, если первого аргумента недостаточно для определения значения выражение: когда первый аргумент функции И оценивается как ложь, общее значение должно быть ложным; и когда первый аргумент функции ИЛИ оценивается как истина, общее значение должно быть истиной.

Not Safe означает, что оператор всегда проверяет каждое условие в предложении, поэтому в приведенных выше примерах 1 / x может быть оценено, когда x фактически равен 0, что вызывает исключение.

Торрес
источник
1
@Torres - Пожалуйста, расширите свой ответ, объяснив «короткое замыкание» и «безопасность». Также является ли «исключающее ИЛИ» и «логическое не» также «не замыкающим»? И почему это называется «логическое не», а не «логическое логическое не»? И почему «логическое НЕ» не сгруппировано с «логическим И» и «логическим ИЛИ»? Хороший ответ, но требует доработки.
tfmontague
@tfmontague, я объяснил, что означает короткое замыкание (отредактировав этот ответ). Жду, пока мое изменение будет "проверено коллегами".
Таслим Осени
что "небезопасно" в отсутствии короткого замыкания? Разве это не должно быть безопаснее, чем использование короткого замыкания? Кстати: вы действительно не объясняете термин "короткое замыкание". это означает, что при "не коротком замыкании" сначала оцениваются все части, затем применяется логическая операция, а при коротком замыкании оценка останавливается, когда первое выражение удовлетворяет условию, например (a || b) не будет оцените b, если a истинно, и операция or вернет true, независимо от того, что такое b.
SCI
26

Я знаю, что здесь много ответов, но все они кажутся немного запутанными. Итак, проведя небольшое исследование из руководства по изучению Java oracle, я придумал три разных сценария, когда использовать && или &. Три сценария логическое И , побитовое И и логическое И .

Логическое И: логическое И (также известное как Условное И) использует оператор && . Это сокращенное значение: если левый операнд ложен, то правый операнд не будет оцениваться.
Пример:

int x = 0;
if (false && (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); // "0"

В приведенном выше примере значение, выводимое на консоль x, будет равно 0, потому что первый операнд в операторе if имеет значение false, следовательно, java не нужно вычислять (1 == ++ x), поэтому x не будет вычисляться.

Поразрядное И: Поразрядное И использует оператор & . Он используется для выполнения побитовой операции над значением. Намного легче увидеть, что происходит, взглянув на операции с двоичными числами, например:

int a = 5;     //                    5 in binary is 0101
int b = 12;    //                   12 in binary is 1100
int c = a & b; // bitwise & preformed on a and b is 0100 which is 4

Как вы можете видеть в примере, когда двоичные представления чисел 5 и 12 выстроены в линию, то предварительно сформированное побитовое И даст только двоичное число, в котором одна и та же цифра в обоих числах имеет 1. Следовательно, 0101 & 1100 == 0100. В десятичной дроби это 5 и 12 == 4.

Логическое И: теперь логический оператор И ведет себя одинаково и по-разному как с побитовым И, так и с логическим И. Мне нравится думать об этом как о преформинге побитового И между двумя логическими значениями (или битами), поэтому он использует оператор & . Логические значения также могут быть результатом логического выражения.

Он возвращает либо истинное, либо ложное значение, во многом аналогично логическому И, но в отличие от логического И оно не замыкается. Причина в том, что для выполнения побитового И он должен знать значения левого и правого операндов. Вот пример:

int x = 0;
if (false & (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); //"1"

Теперь, когда этот оператор if запущен, выражение (1 == ++ x) будет выполнено, даже если левый операнд ложен. Следовательно, значение x будет равно 1, потому что оно увеличилось.

Это также относится к логическому ИЛИ (||), поразрядному ИЛИ (|) и логическому ИЛИ (|). Надеюсь, это устраняет некоторую путаницу.

LynchburgExplorer
источник
to preform that bitwise AND, it must know the value of both left and right operandsМне это не кажется правильным. Для выполнения BITWISE ANDвам не нужно знать правый операнд, чтобы иметь возможность вычислить результат, если левый операнд FALSE. То, что вы объясняете, правильно, но аргументация, которую вы излагаете, не кажется таковой, по крайней мере, мне ..
Корай Тугай
7

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

Tassos Bassoukos
источник
7
-1 за то, что сказал ОП, что он уже знал, и не ответил на вопрос, который он задал.
Альнитак
5

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

Брайан Скотт
источник
1
Неправильно .... Ибо &&он оценивает оба результата, а ||возвращает только если первое условие истинно.
Buhake Sindi
1
А? && оценивает только правую часть выражения, если левая часть уже имеет значение true. В противном случае он перестает оценивать, поскольку первое ложное неявно означает, что результат не может быть истинным. См. Jguru.com/faq/view.jsp?EID=16530
Брайан Скотт,
1
( 2 & 4 )оценивает до false, тогда как ( 2 && 4 )оценивает до true. Как именно такой результат?
Писквор вышел из здания
1
@ Писквор - не на Яве! 2 & 4приводит к целому числу, а не к логическому (в данном случае ноль). 2 && 4не будет компилироваться, && принимает только логические значения. Java не позволяет смешивать логические значения и целые числа: ноль - нет false, falseне равен нулю ...
user85421
1
@BuhakeSindi Неправильно. Потому что &&он оценивает только второй операнд, если первый операнд true.
Marquis of Lorne
2

В Java одиночные операторы &, |, ^,! зависят от операндов. Если оба операнда - целые числа, выполняется побитовая операция. Если оба являются логическими, выполняется «логическая» операция.

Если оба операнда не совпадают, возникает ошибка времени компиляции.

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

if ((a <0) && (b <0)) {...} или аналогично, if ((a <0) || (b <0)) {...}

источник: язык программирования Java 4-е изд

Аарон П.
источник
1

&и |являются поразрядными операторами для целых типов (например int): http://download.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

&&и ||работать только с логическими значениями (и коротким замыканием, как уже говорили другие ответы).

Бруно
источник
3
&и |также являются логическими операторами для логических типов.
Маркиз Лорн
1

Может быть полезно знать, что побитовые операторы AND и побитовые OR всегда вычисляются до использования в одном выражении условного AND и условного OR.

if ( (1>2) && (2>1) | true) // false!
Алексмея
источник
1
Вы имеете в виду приоритет оператора, а не порядок оценки? Я бы предпочел не видеть разницу в приоритетах, используемую в реальном коде. Для этой цели используйте круглые скобки, а не побитовые операторы.
Джон Дворжак
1

&&; || логические операторы .... короткое замыкание

&; | логические логические операторы .... Без короткого замыкания

Переходим к различиям в исполнении по выражениям. Побитовые операторы оценивают обе стороны независимо от результата левой части. Но в случае оценки выражений с помощью логических операторов оценка правого выражения зависит от левого условия.

Например:

int i = 25;
int j = 25;
if(i++ < 0 && j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

Это напечатает i = 26; j = 25, так как первое условие ложно, правое условие игнорируется, так как результат в любом случае ложный, независимо от правого условия. (короткое замыкание)

int i = 25;
int j = 25;
if(i++ < 0 & j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

Но это напечатает i = 26; j = 26,

Никхил
источник
0

Если вычисляется выражение, включающее логический оператор &, оцениваются оба операнда. Затем к операнду применяется оператор &.

Когда вычисляется выражение, включающее оператор &&, вычисляется первый операнд. Если первый операнд оценивается как ложь, оценка второго операнда пропускается.

Если первый операнд возвращает значение true, тогда оценивается второй операнд. Если второй операнд возвращает значение true, тогда к первому и второму операндам применяется оператор &&.

Аналогично для | и ||.

Риши Кеш Патхак
источник
0

В то время как основное отличие состоит в том , что &используется для битовых операций в основном на long, intили byteгде он может быть использован для вида маски, результаты могут отличаться , даже если использовать его вместо логического &&.

Разница более заметна в некоторых сценариях:

  1. Оценка некоторых выражений занимает много времени
  2. Оценить одно из выражений можно, только если предыдущее было истинным
  3. Выражения имеют побочный эффект (преднамеренный или нет)

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

Для второго пункта см. Этот пример:

if ((a != null) & (a.isEmpty()))

Это не работает null, поскольку оценка второго выражения дает NullPointerException. Логический оператор &&ленив, если левый операнд ложен, результат будет ложным независимо от того, какой правый операнд.

Пример для третьего пункта - допустим, у нас есть приложение, которое использует БД без каких-либо триггеров или каскадов. Прежде чем мы удалим объект Building, мы должны изменить здание объекта Department на другое. Предположим также, что статус операции возвращается как логическое значение (истина = успех). Затем:

if (departmentDao.update(department, newBuilding) & buildingDao.remove(building))

Это оценивает оба выражения и, таким образом, выполняет удаление здания, даже если обновление отдела по какой-либо причине не удалось. С &&, он работает по назначению и останавливается после первого сбоя.

Что касается a || b, это эквивалентно !(!a && !b), он останавливается, если aэто правда, никаких дополнительных объяснений не требуется.

Власец
источник