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


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

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);

}
9 75

9 ответов:

The && и || операторы "короткого замыкания", то есть они не оценивают правую сторону, если это не необходимо.

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

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

  • 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;
}

2-я версия использует оператор без короткого замыкания & и бросит NullPointerException если input и null, но 1-я версия вернется false без исключения;

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)

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

например выражение: True / / False

в случае ||, все что нам нужно это одна из сторон чтобы быть правдой. Поэтому, если левая сторона истинна, нет смысла проверять правую сторону, и, следовательно, это не будет проверено вообще.

Аналогично, False & & True

в случае&&, нам нужно обеих сторон, чтобы быть правдой. Поэтому, если левая сторона ложна, нет смысла проверять правую сторону, ответ должен быть ложным. И поэтому это вообще не будет проверяться.

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

этот вид будет короткое замыкание, что означает, если (x < z) оценивает в false, то последний не оценивается,a будет false, иначе && также будет оценивать (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()) { }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

Logical OR: - возвращает true, если хотя бы один из операндов имеет значение true. Оба операнда вычисляются перед применением оператора OR.

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

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

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

Ref. Java 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 дает ноль, но у вас нет способа узнать это без оценки обоих операндов.