Короткое замыкание логического оператора Java


100

Какой набор замыкает накоротко и что именно означает замыкание сложного условного выражения?

public static void main(String[] args) {
  int x, y, z;

  x = 10;
  y = 20;
  z = 30;

  // T T
  // T F
  // F T
  // F F

  //SET A
  boolean a = (x < z) && (x == x);
  boolean b = (x < z) && (x == z);
  boolean c = (x == z) && (x < z);
  boolean d = (x == z) && (x > z);
  //SET B    
  boolean aa = (x < z) & (x == x);
  boolean bb = (x < z) & (x == z);
  boolean cc = (x == z) & (x < z);
  boolean dd = (x == z) & (x > z);

}

4
См. Этот вопрос: stackoverflow.com/questions/7101992/…
Eng.Fouad 06

Ответы:


244

Операторы &&и ||«закорачивают», то есть они не оценивают правую часть, если в этом нет необходимости.

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

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

  • false && ...- не обязательно знать, что такое правая часть, потому что результат может быть только falseнезависимо от значения там
  • true || ...- не обязательно знать, что такое правая часть, потому что результат может быть только trueнезависимо от значения там

Сравним поведение на простом примере:

public boolean longerThan(String input, int length) {
    return input != null && input.length() > length;
}

public boolean longerThan(String input, int length) {
    return input != null & input.length() > length;
}

Вторая версия использует оператор без короткого замыкания &и выдаст NullPointerExceptionif inputis null, но первая версия вернется falseбез исключения.


9
Я просто хотел бы немного расширить этот ответ. Оператор & = является сокращением для выражения x = x &, и поэтому НЕ замыкается. То же самое и с оператором | =.
Stormcloud

11
Одна вещь, которую я хотел бы выделить, | и & - бинарные операторы, а && и || условные (логические) операторы. | и & работают не только с логическими значениями, а && и || работать только с логическими значениями.
Миф

1
Они не только не оценивают выражение с правой стороны, но и код не выполняется, чтобы было что оценивать. Это критический момент для понимания, если бы в противном случае возник побочный эффект.
mckenzm 05

@mckenzm В чем разница между оцененным и выполненным?
Кронен

@Kronen Execution может привести к большему, чем оценка, и вызвать побочный эффект, такой как исключение или задержка, я заплачу, не относящиеся к этому примеру.
mckenzm

9

SET A использует логические операторы короткого замыкания.

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

Например:

// 2 == 2 will never get evaluated because it is already clear from evaluating
// 1 != 1 that the result will be false.
(1 != 1) && (2 == 2)

// 2 != 2 will never get evaluated because it is already clear from evaluating
// 1 == 1 that the result will be true.
(1 == 1) || (2 != 2)

Пожалуйста, укажите, что это так для &&, ||работает по-другому и прекратит вычисление для первого операнда, который вернет истину;)
fge

1
На самом деле, чтобы быть действительно полным, все &&, ||, &и |оценивать слева направо. Для набора логических значений b1, b2, ..., bn версии короткого замыкания прекращают оценку, когда первое из этих логических значений имеет значение true ( ||) или false ( &&). Ба, принцип есть;)
fge 06

@fge: Да, конечно, вы правы. Ваше определение точнее моего. Я обновил свой ответ предложением в вашем комментарии. Надеюсь, ты не против.
afrischke 06

Не беспокойтесь, знания не имеют ценности, если ими не делятся.
fge 06

4

Короткое замыкание означает, что второй оператор не будет проверяться, если первый оператор решит окончательный результат.

Например, выражение: True || Ложь

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

Точно так же False && True

В случае && нам нужно, чтобы обе стороны были True. Таким образом, если левая часть - Ложь, нет смысла проверять правую часть, ответ должен быть Ложь. Следовательно, это вообще не будет проверяться.


4
boolean a = (x < z) && (x == x);

Этот вид будет коротким замыканием, то есть если (x < z)оценивается как ложное, то последнее не оценивается, aбудет ложным, иначе &&также будет оцениваться (x == x).

& является побитовым оператором, но также является логическим оператором И, который не замыкает.

Вы можете проверить их следующим образом (посмотрите, сколько раз метод вызывается в каждом случае):

public static boolean getFalse() {
    System.out.println("Method");
    return false;
}

public static void main(String[] args) {
    if(getFalse() && getFalse()) { }        
    System.out.println("=============================");        
    if(getFalse() & getFalse()) { }
}

-1 Ваш ответ предполагает, что &это всего лишь побитовый оператор, но это не так. Это также логический оператор "или".
Bohemian

@Bohemian: Спасибо за внимание. true & falseоценивается как ложь. Не могли бы вы объяснить этот «логический» или «оператор»? Может быть, я не понимаю, что вы пытаетесь сказать.
Bhesh Gurung 06

Извините - я имел в виду логическое значение AND, а не OR! т.е. true & falseдопустимый синтаксис. -1 удалено :)
Bohemian

4

Проще говоря, короткое замыкание означает прекращение оценки, когда вы знаете, что ответ больше не может измениться. Например, если вы оцениваете цепочку логических ANDs и обнаруживаете FALSEв середине этой цепочки, вы знаете, что результат будет ложным, независимо от того, каковы значения остальных выражений в цепочке. То же самое и с цепочкой ORs: как только вы обнаружите a TRUE, вы сразу узнаете ответ и можете пропустить оценку остальных выражений.

Вы указываете Java, что хотите выполнить короткое замыкание, используя &&вместо &и ||вместо |. Первый набор в вашем посте - это короткое замыкание.

Обратите внимание, что это больше, чем попытка сэкономить несколько циклов процессора: в таких выражениях

if (mystring != null && mystring.indexOf('+') > 0) {
    ...
}

короткое замыкание означает разницу между правильной работой и отказом (в случае, когда mystring имеет значение null).


2

В Java есть два интересных логических оператора, которых нет в большинстве других компьютерных языков. Эти вторичные версии операторов И и ИЛИ известны как логические операторы короткого замыкания . Как видно из предыдущей таблицы, оператор OR приводит к истинному результату, когда A истинно, независимо от того, что такое B.

Точно так же оператор AND приводит к ложному, когда A ложно, независимо от того, что такое B. Если вы используете ||и &&форму, а не |и &форму этих операторов, Java не будет беспокоить , чтобы оценить правый операнд в одиночку. Это очень полезно, когда для правильной работы правый операнд зависит от того, является ли левый истинным или ложным.

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

if ( denom != 0 && num / denom >10)

Поскольку используется форма короткого замыкания AND ( &&), нет риска вызвать исключение времени выполнения из-за деления на ноль. Если бы эта строка кода была написана с использованием единственной &версии AND, обе стороны должны были бы быть оценены, что вызвало бы исключение времени выполнения, когда denomоно равно нулю.

Стандартной практикой является использование коротких форм И и ИЛИ в случаях, связанных с логической логикой, оставляя односимвольные версии исключительно для побитовых операций. Однако из этого правила есть исключения. Например, рассмотрим следующее утверждение:

 if ( c==1 & e++ < 100 ) d = 100;

Здесь использование single &гарантирует, что операция приращения будет применяться к eтому c, равно 1 или нет.


2

Логическое ИЛИ: - возвращает истину, если хотя бы один из операндов оценивается как истина. Оба операнда оцениваются перед применением оператора ИЛИ.

Короткое замыкание ИЛИ: - если левый операнд возвращает истину, он возвращает истину без оценки правого операнда.


2

Между операторами &и есть несколько различий &&. Те же различия применимы к |и ||. Самая важная вещь, о которой следует помнить, это то, что &&это логический оператор, который применяется только к логическим операндам, тогда &как это побитовый оператор, который применяется к целочисленным типам, а также к логическим.

С помощью логической операции вы можете выполнить короткое замыкание, потому что в определенных случаях (например, первый операнд &&бытия falseили первый операнд ||бытия true) вам не нужно оценивать остальную часть выражения. Это очень полезно для выполнения таких вещей, как проверка nullперед доступом к файлу или методу и проверка потенциальных нулей перед делением на них. Для сложного выражения каждая часть выражения вычисляется рекурсивно одинаково. Например, в следующем случае:

(7 == 8) || ( (1 == 3) && (4 == 4))

Оцениваются только выделенные части. Для того, чтобы вычислить ||, сначала проверьте , если 7 == 8есть true. Если бы это было так, правая часть была бы полностью пропущена. Правая сторона проверяет только, 1 == 3есть ли false. Поскольку это так, 4 == 4не нужно проверять, и все выражение оценивается как false. Если бы левая часть была true, например, 7 == 7вместо 7 == 8, вся правая часть была бы пропущена, потому что все ||выражение было бы trueнезависимо.

При побитовой операции вам необходимо оценить все операнды, потому что на самом деле вы просто комбинируете биты. Логические значения фактически представляют собой однобитовые целые числа в Java (независимо от того, как работают внутренние компоненты), и это просто совпадение, что вы можете выполнить короткое замыкание для побитовых операторов в этом особом случае. Причина, по которой вы не можете закоротить общее целое число &или |операцию, заключается в том, что некоторые биты могут быть включены, а некоторые могут быть отключены в любом операнде. Что-то вроде 1 & 2дает ноль, но вы не можете узнать это, не оценив оба операнда.


1
if(demon!=0&& num/demon>10)

Поскольку используется форма короткого замыкания AND (&&), нет риска вызвать исключение во время выполнения, когда демон равен нулю.

Ref. Пятое издание Java 2 от Герберта Шильдта

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.