Java 逻辑运算符短路
Posted
技术标签:
【中文标题】Java 逻辑运算符短路【英文标题】:Java logical operator short-circuiting 【发布时间】:2022-01-03 11:08:59 【问题描述】:哪个集合短路了,复杂条件表达式短路到底是什么意思?
public static void main(String[] args)
int x, y, z;
x = 10;
y = 20;
z = 30;
// T T
// T F
// F T
// F F
//SET A
boolean a = (x < z) && (x == x);
boolean b = (x < z) && (x == z);
boolean c = (x == z) && (x < z);
boolean d = (x == z) && (x > z);
//SET B
boolean aa = (x < z) & (x == x);
boolean bb = (x < z) & (x == z);
boolean cc = (x == z) & (x < z);
boolean dd = (x == z) & (x > z);
【问题讨论】:
看到这个问题:***.com/questions/7101992/… Set B 不使用逻辑运算符。它们使用按位运算符比较操作数的每一位。 【参考方案1】:&&
和 ||
运算符“短路”,这意味着如果没有必要,它们不会计算右侧。
&
和 |
运算符在用作逻辑运算符时,总是计算两边。
每个算子只有一种短路情况,分别是:
false && ...
- 不需要知道右边是什么,因为无论那里的值如何,结果只能是 false
true || ...
- 不需要知道右边是什么,因为无论那里的值如何,结果只能是 true
让我们用一个简单的例子来比较一下行为:
public boolean longerThan(String input, int length)
return input != null && input.length() > length;
public boolean longerThan(String input, int length)
return input != null & input.length() > length;
第二版使用非短路运算符&
,如果input
是null
,将抛出NullPointerException
,但第一版将毫无例外地返回false
。
【讨论】:
我只是想扩展一下这个答案。 &= 运算符是 x = x & 表达式的简写,因此 is 不会短路。 |= 运算符也是如此。 我想强调一件事,|和 & 是二元运算符,而 && 和 ||是条件(逻辑)运算符。 |和 & 不仅仅处理布尔值,而 && 和 ||仅适用于布尔值。 他们不仅不评估右侧的表达式,而且不执行代码以进行任何评估。这是了解是否会产生副作用的关键点。 @mckenzm 评估和执行有什么区别? @Kronen 执行可能会导致超过评估,并产生副作用,例如异常或延迟,我将支付与此示例无关的费用。【参考方案2】:SET A 使用短路布尔运算符。
在布尔运算符的上下文中,“短路”意味着对于一组布尔值 b1、b2、...、bn,只要这些布尔值中的第一个为真,短路版本就会停止计算(||) 或假 (&&)。
例如:
// 2 == 2 will never get evaluated because it is already clear from evaluating
// 1 != 1 that the result will be false.
(1 != 1) && (2 == 2)
// 2 != 2 will never get evaluated because it is already clear from evaluating
// 1 == 1 that the result will be true.
(1 == 1) || (2 != 2)
【讨论】:
请说明&&
的情况,||
的工作方式不同,将停止对第一个返回 true 的操作数进行评估;)
事实上,要真正完整,所有&&
、||
、&
和|
从左到右计算。对于一组布尔值 b1、b2、...、bn,当这些布尔值中的第一个为真 (||
) 或假 (&&
) 时,短路版本将停止评估。呸,原理就在那里;)
@fge:是的,你当然是对的。你的定义比我的更准确。我已经用您评论中的句子更新了我的答案。希望你不要介意。
不用担心,知识不分享就没有价值。【参考方案3】:
短路意味着如果第一个运算符决定最终结果,则不会检查第二个运算符。
例如表达式为:真||假的
在 || 的情况下,我们只需要 一侧 为真。因此,如果左侧为真,则检查右侧没有意义,因此根本不会检查。
同样,假&&真
在 && 的情况下,我们需要 双方 为 True。因此,如果左侧为 False,则检查右侧没有意义,答案必须为 False。因此根本不会检查。
【讨论】:
【参考方案4】:boolean a = (x < z) && (x == x);
这种会短路,意思是如果(x < z)
评估为假,则不评估后者,a
将为假,否则&&
也会评估(x == x)
。
&
是一个位运算符,也是一个不会短路的布尔 AND 运算符。
您可以通过以下方式对其进行测试(查看在每种情况下该方法被调用了多少次):
public static boolean getFalse()
System.out.println("Method");
return false;
public static void main(String[] args)
if(getFalse() && getFalse())
System.out.println("=============================");
if(getFalse() & getFalse())
【讨论】:
-1 您的回答表明&
是 only 位运算符,但事实并非如此。它也是一个布尔“或”运算符。
@Bohemian:感谢您的提醒。 true & false
评估为假。你能解释一下这个“布尔”或“运算符”吗?可能我没听懂你想说的。
抱歉 - 我的意思是布尔值 AND
,而不是 OR
!即true & false
是有效的语法。 -1 已删除 :)【参考方案5】:
简单来说,短路意味着一旦你知道答案不能再改变就停止评估。例如,如果您正在评估一个逻辑链 AND
s 并且您在该链的中间发现了一个 FALSE
,那么您知道结果将是错误的,无论其余的值是什么链中的表达式。 OR
s 链也是如此:一旦发现 TRUE
,您就会立即知道答案,因此您可以跳过对其余表达式的求值。
您通过使用&&
而不是&
和||
而不是|
向Java 表明您想要短路。您帖子中的第一组是短路。
请注意,这不仅仅是为了节省一些 CPU 周期:在这样的表达式中
if (mystring != null && mystring.indexOf('+') > 0)
...
短路意味着正确操作和崩溃之间的区别(在 mystring 为空的情况下)。
【讨论】:
【参考方案6】:Java 提供了大多数其他计算机语言中没有的两个有趣的布尔运算符。 AND 和 OR 的这些辅助版本称为短路逻辑运算符。从上表可以看出,无论 B 是什么,当 A 为真时,OR 运算符的结果为真。
同样,无论 B 是什么,当 A 为假时,AND 运算符都会导致假。如果您使用||
和&&
形式,而不是这些运算符的|
和&
形式,Java 将不会费心单独计算右侧操作数。当右侧操作数依赖于左侧操作数为真或假才能正常运行时,这非常有用。
例如,以下代码片段展示了如何利用短路逻辑评估来确保除法运算在评估之前有效:
if ( denom != 0 && num / denom >10)
由于使用了 AND (&&
) 的短路形式,因此不存在因除以零而导致运行时异常的风险。如果这行代码是使用单个 &
版本的 AND 编写的,则必须对双方进行评估,从而在 denom
为零时导致运行时异常。
在涉及布尔逻辑的情况下,使用 AND 和 OR 的短路形式是标准做法,而单字符版本专门用于按位运算。但是,此规则也有例外。例如,考虑以下语句:
if ( c==1 & e++ < 100 ) d = 100;
这里,使用单个&
确保递增操作将应用于e
,无论c
是否等于1。
【讨论】:
【参考方案7】:逻辑或 :- 如果至少有一个操作数计算为真,则返回真。在应用 OR 运算符之前对两个操作数进行求值。
Short Circuit OR :- 如果左侧操作数返回 true,则返回 true 而不评估右侧操作数。
【讨论】:
【参考方案8】:&
和 &&
运算符之间存在一些差异。同样的差异适用于|
和||
。最重要的是要记住&&
是一个逻辑 运算符,仅适用于布尔操作数,而&
是一个位 运算符,适用于整数类型和布尔值。
通过逻辑运算,您可以进行短路,因为在某些情况下(例如&&
的第一个操作数是false
,或者||
的第一个操作数是true
),您不需要评估表达式的其余部分。这对于在访问字段或方法之前检查null
以及在除以之前检查潜在的零非常有用。对于复杂的表达式,表达式的每个部分都以相同的方式递归计算。比如下面这种情况:
只评估强调的部分。要计算||
,首先检查7 == 8
是否为true
。如果是,则将完全跳过右侧。右侧仅检查1 == 3
是否为false
。既然是,4 == 4
不需要检查,整个表达式的计算结果为false
。如果左侧是true
,例如7 == 7
而不是 7 == 8
,整个右侧将被跳过,因为整个 ||
表达式将是 true
无论如何。
使用按位运算,您需要计算所有操作数,因为您实际上只是在组合位。布尔值实际上是 Java 中的一位整数(不管内部如何工作),在这种特殊情况下,您可以对位运算符进行短路只是巧合。不能将通用整数 &
或 |
操作短路的原因是,任一操作数中的某些位可能打开而某些位可能关闭。 1 & 2
之类的结果为零,但如果不评估两个操作数,您就无法知道这一点。
【讨论】:
【参考方案9】:if(demon!=0&& num/demon>10)
由于使用了 AND(&&) 的短路形式,所以当 demo 为零时不会导致运行时异常。
参考。 Herbert Schildt 的 Java 2 第五版
【讨论】:
【参考方案10】:来自 docs.oracle 的文档
由于逻辑表达式是从左到右计算的,因此使用以下规则测试它们是否存在可能的“短路”计算:
false && 短路评估为 false。
真||任何东西都被短路评估为真。
逻辑规则保证这些评估总是正确的。请注意,上述表达式的任何部分都不会被计算,因此这样做的任何副作用都不会生效。
https://docs.oracle.com/cd/E57185_01/HIRUG/ch31s05s01.html
【讨论】:
以上是关于Java 逻辑运算符短路的主要内容,如果未能解决你的问题,请参考以下文章