&& (AND) и || (OR) в операторах IF

Мой вопрос может быть очень простым, но все же я думаю, что стоит спросить. У меня есть следующий код:

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

Ответ 1

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

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

или, наоборот,

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

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

Ответ 2

В 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

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

Ответ 4

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

Раздел 15:23, Условный-И оператор (& &), говорит:

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

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

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

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

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

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

Ответ 5

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

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

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

будет не бросить a NullPointerException!

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

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

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

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

Ответ 9

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

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

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