Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: AzimuthОтветов: 9

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

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 верно во втором случае?

javaif-statement

Ответы

Ответ 1 · рейтинг 218 · Andreas Dolk

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

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

или наоборот

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

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

Ответ 2 · рейтинг 70 · Hardcoded

В 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 нельзя оптимизировать, потому что он зависит от обоих параметров.

Ответ 3 · рейтинг 27 · Peter van der Heijden

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

Ответ 4 · рейтинг 20 · Cowan

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

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

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

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

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

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

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

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

Ответ 5 · рейтинг 9 · user3211238

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

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

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

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

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

Ответ 6 · рейтинг 7 · Romain Linsolas

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

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

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

не будет NullPointerException!

Ответ 7 · рейтинг 4 · abyx

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

Ответ 8 · рейтинг 4 · fortran

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

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

Ответ 9 · Peter Lawrey

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

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы