У меня есть следующий код:
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
истинно во втором случае?
Нет, это не будет оценено. И это очень полезно. Например, если вам нужно проверить, не является ли String нулевым или пустым, вы можете написать:
if (str != null && !str.isEmpty()) {
doSomethingWith(str.charAt(0));
}
или наоборот
if (str == null || str.isEmpty()) {
complainAboutUnusableString();
} else {
doSomethingWith(str.charAt(0));
}
Если бы у нас не было «коротких замыканий» в Java, мы получили бы много NullPointerExceptions в приведенных выше строках кода.
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 не может быть оптимизирован, потому что это зависит от обоих параметров.
Нет, он не будет проверяться. Такое поведение называется short-circuit evaluation и является особенностью многих языков, включая Java.
Все ответы здесь отличные, но, чтобы проиллюстрировать, откуда это, для таких вопросов хорошо перейти к источнику: спецификации языка Java.
Раздел 15:23, Условный оператор (& &), говорит:
& & оператор похож на & (& # 167; 15.22.2), но оценивает его правый операнд только в том случае, если значение его левого операнда истинно. [...] Во время выполнения выражение левого операнда оценивается первым [...] если результирующее значение является ложным, значение условного и выражения является ложным, а правое выражение операнда не оценивается. Если значение левого операнда истинно, то оценивается правое выражение [...] результирующее значение становится значением условного выражения. Таким образом, & & вычисляет тот же результат, что и & на логических операндах. Он отличается только тем, что правостороннее выражение оценивается условно, а не всегда.
И аналогично, Раздел 15:24, Условный-или оператор (||), говорит:
Оператор || похож на | (& # 167; 15.22.2), но оценивает его правый операнд только в том случае, если значение его левого операнда ложно. [...] Во время выполнения выражение левого операнда оценивается первым; [...] если результирующее значение является истинным, значение условного или выражения является истинным, а правое оперное выражение не оценивается. Если значение левого операнда неверно, то оценивается правое выражение; [...] результирующее значение становится значением условного или выражения. Таким образом, | | вычисляет тот же результат, что и | на логических или логических операндах. Он отличается только тем, что правостороннее выражение оценивается условно, а не всегда.
Может быть, немного повторяющийся, но лучшее подтверждение того, как именно они работают. Аналогично условный оператор (?:) оценивает только соответствующую «половину» (левая половина, если значение истинно, правая половина, если оно ложно), позволяя использовать выражения типа:
int x = (y == null) ? 0 : y.getFoo();
без NullPointerException.
Нет, если a истинно (в тесте or
), то b не будет проверяться, так как результат проверки всегда будет истинным, каким бы ни было значение выражения b.
Составьте простой тест:
if (true || ((String) null).equals("foobar")) {
...
}
не будет выбрасывать NullPointerException
!
Короткая замыкание здесь означает, что второе условие не будет оценено.
Если (A & & B) приведет к короткому замыканию, если A является False.
Если (A & & B) не приведет к короткому замыканию, если A является True.
Если (A || B) приведет к короткому замыканию, если A является True.
Если (A || B) не приведет к короткому замыканию, если A является False.
Да, оценка короткого замыкания для логических выражений является поведением по умолчанию во всем семействе C-like.
Интересный факт заключается в том, что Java также использует &
& `в качестве логических операндов (они перегружены, а
int` - ожидаемые побитовые операции) для оценки всех терминов в выражении, что также полезно, когда вам нужны побочные эффекты.
Это восходит к основному различию между & и & &, | и ||
Кстати, вы выполняете одни и те же задачи много раз. Не уверен, что эффективность является проблемой. Вы можете удалить некоторые из дублирований.
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);
}