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

Я знаю правила для && и ||, но что такое & и |? Пожалуйста, объясните мне это на примере.


person Sumithra    schedule 25.10.2010    source источник


Ответы (11)


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

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) относительно различного поведения оператора на основе его входных данных.

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

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

Это не:

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

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

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

person Justin Niessner    schedule 25.10.2010
comment
хотел уточнить .. и вернет 1, только если ОБА равны 1? Итак, 101 и 001 будут 001? Правильно? - person gideon; 25.10.2010
comment
@giddy @Jonathon - я обновил свои значения, чтобы лучше показать эту ситуацию. - person Justin Niessner; 25.10.2010
comment
неполные: они также являются ЛОГИЧЕСКИМИ операторами (для логических значений). - person user85421; 25.10.2010
comment
@Carlos- Нет. Они все еще побитовые операторы. Они просто ведут себя так же, как логические операторы без короткого замыкания. Есть разница. - person Justin Niessner; 25.10.2010
comment
и что такое логические операторы без короткого замыкания? Операторы & и | (спрашивает OP) - это целочисленные побитовые операторы (JLS 15.22.1) и логические операторы (JLS 15.22.2). Или Спецификация языка Java неверна? - person user85421; 26.10.2010
comment
@Карлос - Хороший звонок. Спасибо, что указали на нужное место в спецификации. Я обновил свой ответ. - person Justin Niessner; 26.10.2010
comment
Вы можете улучшить ответ, подчеркнув, что это безопасно, а это небезопасно. Лучше иметь вызов метода (который будет иметь побочный эффект) вместо доступа к свойству, чтобы показать, что последнее может быть небезопасным. - person Jaywalker; 26.10.2010
comment
Ссылка на спецификацию не работает с переходом на Oracle. Новые ссылки находятся вокруг документов. .oracle.com/javase/specs/jls/se7/html/. Я поддерживаю замечание @Jaywalker. && может быть небезопасным, если выражение после && является операцией, которую вы хотели бы выполнить в любом случае. Некоторые разъяснения были бы полезны. - person Chris; 28.12.2012

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

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

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

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

person Torres    schedule 25.10.2010
comment
@Torres - Пожалуйста, расширьте свой ответ, объяснив короткое замыкание и безопасность. И является исключительным или и логичным и незамыкающим? И почему оно называется логическим not, а не булевым логическим not? И почему логическое НЕ не группируется с логическим И и логическим ИЛИ? Хороший ответ, но нужно работать. - person tim-montague; 04.11.2017
comment
@tfmontague, я объяснил, что означает короткое замыкание (отредактировав этот ответ). Жду, пока мое редактирование будет проверено экспертами. - person Taslim Oseni; 17.12.2017
comment
что небезопасного в том, чтобы не закоротить? разве это не должно быть безопаснее, чем использование коротких замыканий? кстати: вы действительно не объясняете термин короткого замыкания. это означает, что на не коротком замыкании сначала оцениваются все части, затем применяется логическая операция, а на коротком замыкании оценка останавливается, когда первое выражение удовлетворяет условию, например (a || b) не будет вычислять b , если a истинно и операция or вернет true, независимо от того, что такое b. - person SCI; 07.06.2018

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

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

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

В приведенном выше примере значение, напечатанное на консоли x, будет равно 0, потому что первый операнд в операторе if ложен, поэтому 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, потому что оно было увеличено.

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

person LynchburgExplorer    schedule 08.04.2016
comment
to preform that bitwise AND, it must know the value of both left and right operands Мне это кажется неправильным. Чтобы выполнить BITWISE AND, вам не нужно знать правый операнд, чтобы иметь возможность вычислить результат, если левый операнд равен FALSE. То, что вы объясняете, верно, но рассуждения, которые вы излагаете, не кажутся таковыми, по крайней мере мне. - person Koray Tugay; 04.02.2018

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

person Tassos Bassoukos    schedule 25.10.2010
comment
-1 за то, что рассказал ОП то, что он уже знал, и не ответил на вопрос, который он на самом деле задал. - person Alnitak; 25.10.2010

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

person Brian Scott    schedule 25.10.2010
comment
Неправильно.... Для && он оценивает оба результата, а || возвращает значение только в том случае, если первое условие истинно. - person Buhake Sindi; 25.10.2010
comment
Хм? && оценивает только правую часть выражения, если левая часть уже имеет значение true. В противном случае он прекращает оценку, поскольку первая ложь неявно означает, что результат не может быть истинным. См. jguru.com/faq/view.jsp?EID=16530. - person Brian Scott; 25.10.2010
comment
( 2 & 4 ) оценивается как false, тогда как ( 2 && 4 ) оценивается как true. Как именно это тот же результат? - person Piskvor left the building; 25.10.2010
comment
@Piskvor - не на Java! 2 & 4 возвращает целое число, а не логическое (в данном случае ноль). 2 && 4 не будет компилироваться, && принимает только логические значения. Java не позволяет смешивать логические значения и целые числа: ноль — это не false, false — это не ноль... - person user85421; 26.10.2010
comment
@Brian Scott: если бы вы уточнили свой ответ с помощью для логических значений, добавленных KarlP, это был бы очень хороший ответ. Я все же проголосовал за него, чтобы сбалансировать неоправданные отрицательные голоса. - person Sean Patrick Floyd; 26.10.2010
comment
@BuhakeSindi Неправильно. Для && он оценивает второй операнд только в том случае, если первый операнд равен true. - person user207421; 26.09.2016

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

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

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

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

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

person aaron p.    schedule 04.03.2015

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

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

person Bruno    schedule 25.10.2010
comment
& и | также являются логическими операторами для логических типов. - person user207421; 26.09.2016

Возможно, будет полезно знать, что побитовые операторы И и побитовые ИЛИ всегда оцениваются перед условным И и условным ИЛИ, используемыми в одном и том же выражении.

if ( (1>2) && (2>1) | true) // false!
person alexmeia    schedule 04.09.2013
comment
Вы имеете в виду приоритет оператора, а не порядок оценки? Я бы предпочел не видеть разницу в приоритетах, используемую в реальном коде. Используйте для этой цели круглые скобки, а не побитовые операторы. - person John Dvorak; 04.09.2013

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

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

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

Например:

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,

person Nickhil    schedule 15.06.2015

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

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

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

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

person RishiKesh Pathak    schedule 03.12.2014

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

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

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

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

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

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

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

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

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

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

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

person Vlasec    schedule 09.12.2014