&& (И) и || (ИЛИ) в операторах ЕСЛИ

У меня такой код:

if(!partialHits.get(req_nr).containsKey(z) || partialHits.get(req_nr).get(z) < tmpmap.get(z)){  
    partialHits.get(z).put(z, tmpmap.get(z));  
}

где partialHits - это HashMap.
Что произойдет, если первое утверждение истинно? Будет ли Java проверять второе утверждение? Потому что для того, чтобы первое утверждение было истинным, HashMap не должен содержать заданный ключ, поэтому, если второй оператор будет проверен, я получу NullPointerException.
Итак, простыми словами, если у нас есть следующий код

if(a && b)  
if(a || b)

будет ли Java проверять b, если a ложно в первом случае и если a верно во втором случае?


person Azimuth    schedule 25.11.2009    source источник


Ответы (9)


Нет, оцениваться не будет. И это очень полезно. Например, если вам нужно проверить, не является ли строка нулевой или пустой, вы можете написать:

if (str != null && !str.isEmpty()) {
  doSomethingWith(str.charAt(0));
}

или наоборот

if (str == null || str.isEmpty()) {
  complainAboutUnusableString();
} else {
  doSomethingWith(str.charAt(0));
}

Если бы у нас не было «коротких замыканий» в Java, мы бы получили много исключений NullPointerExceptions в приведенных выше строках кода.

person Andreas Dolk    schedule 25.11.2009
comment
Существуют ли побитовые сравнения, чтобы вы могли оценивать оба выражения? т.е. если (str! = null | str.isEmpty ())? (конечно, это не практический пример, на самом деле это глупо, но идею вы поняли) - person Kezzer; 27.11.2009
comment
Пока выражения не имеют побочных эффектов, семантика короткого замыкания логически эквивалентна полной оценке. То есть, если A истинно, вы знаете, что A || B истинно, без необходимости оценивать B. Единственный раз, когда это будет иметь значение, - это если выражение имеет побочные эффекты. Что касается других операторов, вы можете использовать * и + как логические and и or; ((A?1:0) * (B?1:0)) == 1, ((A?1:0) + (B?1:0)) > 0. Вы даже можете сделать xor: ((A?1:0) + (B?1:0)) == 1. - person outis; 27.11.2009
comment
@Kezzer: это действительно побитовое сравнение? Я думаю, что это boolean (логический) оператор. Он отличается от оператора bitwise (целое число), несмотря на тот же символ ... - person user85421; 27.11.2009
comment
Удобный трюк, когда вы хотите переключаться между '&&' и '||' выражения должны отрицать все выражение таким образом, что: !(str != null && !str.isEmpty()) становится: (str !(!=) null !(&&) !(!)str.isEmpty()), а затем: (str == null || str.isEmpty()), потому что: !(!=) is == !(&&) is || !(!) eliminates itself другие полезные отрицания: !(<) is >= !(>) is <= и наоборот - person egallardo; 09.03.2013

В Java есть 5 различных логических операторов сравнения: &, &&, |, ||, ^

& и && являются операторами "и", | и || операторы "или", ^ - "xor"

Одиночные будут проверять каждый параметр, независимо от значений, перед проверкой значений параметров. Двойные сначала проверят левый параметр и его значение, и если true (||) или false (&&) оставят второй нетронутым. Звук компилированный? Простой пример должен прояснить это:

Приведено для всех примеров:

 String aString = null;

И:

 if (aString != null & aString.equals("lala"))

Оба параметра проверяются перед выполнением оценки, и для второго параметра будет выброшено исключение NullPointerException.

 if (aString != null && aString.equals("lala"))

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

То же для OR:

 if (aString == null | !aString.equals("lala"))

Также вызовет исключение NullPointerException.

 if (aString == null || !aString.equals("lala"))

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

XOR нельзя оптимизировать, потому что он зависит от обоих параметров.

person Hardcoded    schedule 27.11.2009
comment
В Java есть 4 различных логических оператора сравнения: &, &&, |, || ... Вы забываете ^ (xor). - person aioobe; 10.06.2010
comment
О, я не знал, что он тоже проверяет логические логические значения. Пока использовал его только для битовых масок. - person Hardcoded; 16.06.2010

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

person Peter van der Heijden    schedule 25.11.2009

Все ответы здесь прекрасны, но, чтобы проиллюстрировать, откуда это взялось, для подобных вопросов полезно обратиться к источнику: Спецификации языка Java.

Раздел 15:23, Оператор условного И (&&), говорит:

Оператор && подобен & (§15.22.2), но вычисляет свой правый операнд, только если значение его левого операнда истинно. [...] Во время выполнения сначала оценивается выражение левого операнда [...], если результирующее значение ложно, значение условного выражения и выражения ложно, а выражение правого операнда не оценивается . Если значение левого операнда истинно, тогда вычисляется правое выражение [...], результирующее значение становится значением условного выражения и. Таким образом, && вычисляет тот же результат, что и & для логических операндов. Он отличается только тем, что выражение правого операнда вычисляется условно, а не всегда.

И аналогично, Раздел 15:24, Оператор условного ИЛИ ( ||), говорит:

|| оператор похож на | (§15.22.2), но оценивает свой правый операнд, только если значение его левого операнда ложно. [...] Во время выполнения сначала вычисляется выражение левого операнда; [...] если результирующее значение истинно, значение выражения условного ИЛИ истинно, а выражение правого операнда не оценивается. Если значение левого операнда ложно, то вычисляется правое выражение; [...] результирующее значение становится значением условного или выражения. Таким образом, || вычисляет тот же результат, что и | для логических или логических операндов. Он отличается только тем, что выражение правого операнда вычисляется условно, а не всегда.

Возможно, немного повторяется, но это лучшее подтверждение того, как именно они работают. Точно так же условный оператор (? :) оценивает только соответствующую «половину» (левая половина, если значение истинно, правая половина, если оно ложно), что позволяет использовать такие выражения, как:

int x = (y == null) ? 0 : y.getFoo();

без исключения NullPointerException.

person Cowan    schedule 25.11.2009

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

Если (A && B) приведет к короткому замыканию, если A имеет значение False.

Если (A && B) не приведет к короткому замыканию, если A истинно.

Если (A || B) приведет к короткому замыканию, если A истинно.

Если (A || B) не приведет к короткому замыканию, если A имеет значение False.

person user3211238    schedule 19.01.2014

Нет, если a истинно (в проверке or), b не будет проверяться, так как результат проверки всегда будет истинным, каким бы ни было значение выражения b.

Сделайте простой тест:

if (true || ((String) null).equals("foobar")) {
    ...
}

не будет NullPointerException!

person Romain Linsolas    schedule 25.11.2009

Нет, не будет, Java произведет короткое замыкание и прекратит оценку, как только узнает результат.

person abyx    schedule 25.11.2009

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

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

person fortran    schedule 27.11.2009
comment
Это интересно запомнить: например, учитывая метод changeData (data), который возвращает логическое значение, тогда: if (a.changeData (data) || b.changeData (data)) {doSomething (); } не выполняет changeData для b, если a.changeData () возвращает true, но если (a.changeData (data) | b.changeData (data)) {doSomething ()} выполняет changeData () как для a, так и для b, даже если тот, который был вызван, вернул истину. - person Sampisa; 15.02.2017

Это восходит к основному различию между & и &&, | и ||

Кстати, вы выполняете одни и те же задачи много раз. Не уверен, что проблема в эффективности. Вы можете удалить часть дублирования.

Z z2 = partialHits.get(req_nr).get(z); // assuming a value cannout be null.
Z z3 = tmpmap.get(z); // assuming z3 cannot be null.
if(z2 == null || z2 < z3){   
    partialHits.get(z).put(z, z3);   
} 
person Peter Lawrey    schedule 11.05.2010