Короткое замыкание логического оператора 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 ответов


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

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

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

  • 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 is null, но 1-я версия вернется false без исключения;


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

что означает "короткое замыкание" в контексте булевых операторов, так это то, что для набора булевых B1, b2,..., bn, версии короткого замыкания прекратят оценку, как только первое из этих булевых значений будет true ( | | ) или false (&&).

например:

// 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).

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

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

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, и вы обнаружите FALSE в середине этой цепи, вы знаете, результат будет ложным, независимо от того, каковы значения остальных выражений в цепочке. То же самое касается цепочки ORs: как только вы обнаружите TRUE, вы знаете ответ сразу, и поэтому вы можете пропустить оценка остальных выражений.

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

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

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

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


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

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

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

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

С момента короткого замыкания формы и (&&) используется, нет риска возникновения исключения времени выполнения от деления на ноль. Если бы эта строка кода была написана с использованием single & версия 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 (&&), нет риска возникновения исключения во время выполнения, когда demon равен нулю.

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


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

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

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

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

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