我有以下代码:
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)
如果在第一种情况下 a
为假,而在第二种情况下 a
为真,Java 会检查 b
吗?
不,它不会被评估。这非常有用。例如,如果您需要测试一个 String 是否为 null 或为空,您可以编写:
if (str != null && !str.isEmpty()) {
doSomethingWith(str.charAt(0));
}
或者,反过来
if (str == null || str.isEmpty()) {
complainAboutUnusableString();
} else {
doSomethingWith(str.charAt(0));
}
如果我们在 Java 中没有“短路”,我们会在上面的代码行中收到很多 NullPointerExceptions。
Java 有 5 种不同的布尔比较运算符:&、&&、|、||、^
& 和 && 是“和”运算符,|和 || “或”运算符,^ 是“异或”
在检查参数值之前,单个参数将检查每个参数,而不管值如何。双重的将首先检查左边的参数及其值,如果 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 无法优化,因为它取决于两个参数。
^
(xor)。
这里的所有答案都很好,但是为了说明这是从哪里来的,对于这样的问题,最好去源头:Java 语言规范。
Section 15:23, Conditional-And operator (&&),说:
&& 运算符类似于 &(第 15.22.2 节),但仅当其左侧操作数的值为真时才计算其右侧操作数。 [...] 在运行时,首先计算左侧操作数表达式 [...] 如果结果值为 false,则条件与表达式的值为 false 并且不计算右侧操作数表达式.如果左侧操作数的值为真,则计算右侧表达式 [...] 结果值成为条件与表达式的值。因此, && 在布尔操作数上计算与 & 相同的结果。它的不同之处仅在于右手操作数表达式是有条件地计算而不是总是计算。
同样,Section 15:24, Conditional-Or operator (||) 说:
||运算符就像 | (§15.22.2),但仅当其左侧操作数的值为假时才评估其右侧操作数。 [...] 在运行时,首先计算左侧操作数表达式; [...] 如果结果值为真,则条件或表达式的值为真,并且不计算右侧操作数表达式。如果左侧操作数的值为 false,则计算右侧表达式; [...] 结果值成为条件或表达式的值。因此,||计算与 | 相同的结果在布尔或布尔操作数上。它的不同之处仅在于右手操作数表达式是有条件地计算而不是总是计算。
可能有点重复,但最好确认它们是如何工作的。类似地,条件运算符(?
int x = (y == null) ? 0 : y.getFoo();
没有 NullPointerException。
这里的短路意味着不会评估第二个条件。
If ( A && B ) 如果 A 为 False 将导致短路。
If ( A && B ) 如果 A 为真,则不会导致短路。
If ( A || B ) 如果 A 为真,将导致短路。
If ( A || B ) 如果 A 为 False,则不会导致短路。
不,如果 a 为真(在 or
测试中),则不会测试 b,因为无论 b 表达式的值是什么,测试的结果都将始终为真。
做一个简单的测试:
if (true || ((String) null).equals("foobar")) {
...
}
将不会抛出 NullPointerException
!
不,它不会,一旦知道结果,Java 就会短路并停止评估。
是的,布尔表达式的短路求值是所有类 C 系列的默认行为。
一个有趣的事实是,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);
}
*
和+
作为逻辑and
和or
;((A?1:0) * (B?1:0)) == 1
、((A?1:0) + (B?1:0)) > 0
。你甚至可以做xor
:((A?1:0) + (B?1:0)) == 1
。boolean
(逻辑)运算符。它与bitwise
(整数)运算符不同,尽管具有相同的符号......!(str != null && !str.isEmpty())
变为:(str !(!=) null !(&&) !(!)str.isEmpty())
然后:(str == null || str.isEmpty())
因为:!(!=) is ==
!(&&) is ||
!(!) eliminates itself
其他有用的否定是:!(<) is >=
!(>) is <=
和反之亦然