Короткое замыкание логического оператора 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 ответов:
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()) { } }
иными словами, короткое замыкание означает остановку оценки, как только вы знаете, что ответ больше не может измениться. Например, если вы оцениваете цепочку логических
AND
s и вы обнаружите aFALSE
в середине этой цепи, вы знаете, результат будет ложным, независимо от того, каковы значения остальных выражений в цепочке. То же самое касается цепочкиOR
s: как только вы обнаружите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
дает ноль, но у вас нет способа узнать это без оценки обоих операндов.