我理解&&
和||
在Java中被短路(而&
和|
则没有)
但是,我不明白为什么以下代码(以短路OR开始但以&&条件结束)也被短路:
String x, y;
if ( x.contains("this") || x.contains("that") && y.contains("something else")!= true)
我认为即使条件x.contains("this")
评估为真,程序仍然需要评估最后一个条件y.contains("something else") != true
,因为在最后一个条件之前有&&运算符。但显然事实并非如此。
有谁能解释为什么?
这里有两个因素来确定评估顺序:
由于&&
的优先级高于||
,因此运算符&&
“更接近其操作数”,因此您的表达式解析如下:
因为&&
和||
运算符都是从左到右的关联*,所以Java从左到右评估这个表达式,一旦确定结果就停止。如果字符串包含"this"
子字符串,则评估将在不评估&&
的情况下停止。
注意:如果您不确定操作的顺序,则可以通过括号部分谓词来强制执行所需的顺序。如果表达对你来说并不完全明显,很有可能它对其他读者来说是不明显的,所以添加一些额外的括号是个好主意。
*一些运营商是从右到左的关联。例如,赋值运算符a[i] = b + c
在评估b + c
之前评估a[i]
。感谢T.J. Crowder的好评。
这是因为运营商优先。
你的(a || b && c)的等价形式是(a ||(b && c))
参看https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
...即使条件
x.contains("this")
评估为真,程序仍需要评估最后一个条件y.contains("something else") != true
...
不。 :-)表达式中||
的操作数是
x.contains("this")
和
x.contains("that") && y.contains("something else")!= true
...因为&&
的优先级高于||
(details)。所以,如果你有a || b && c
,那就是a || (b && c)
(就像a + b * c
是a + (b * c)
而不是(a + b) * c
)。优先级定义操作数的分组方式。
如果您希望表达式以不同方式分组,则可以使用()
对其进行分组。
if ( (x.contains("this") || x.contains("that")) && y.contains("something else")!= true)
它与operator precedence有关。大多数标准运算符都是二进制运算符,即它们采用两个输入并产生输出。每当有一个包含两个以上运算符的表达式时,编译器就会使用优先级和关联性规则来确定如何将该表达式转换为清楚每个操作具有哪些输入的表达式。
在你的情况下,你有一个像A || B && C
的表达式。 &&
的优先级高于||
,因此编译器会将其解释为A || (B && C)
,而不是(A || B) && C
,只需查看表达式就可以得到它。
这意味着A
足以让整个表达式成为现实。
这是语法在java中的工作方式,因为&&操作在||之前分组因此,当它读取等式(A || B && C)时,它只能看到比较A || D(其中D实际上是B && C)。因此,当A被评估为True时,它甚至不需要评估B && C.请参阅此链接以获取有关操作顺序的进一步语法相关问题https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
&&
是一个优先级高于||
的运营商。
优先级较高的运算符在优先级较低的运算符之前进行求值。
所以在这里 :
if ( x.contains("this") || x.contains("that") && y.contains("something else")!= true)
这两个表达式一起评估:
x.contains("that") && y.contains("something else")!= true
因此,您将获得一个带有以下形式的条件语句:if (something || somethingElse)
something
是true
,所以somethingElse
永远不会被评估。
整个条件语句是true
。
Java有一些operator precedence。您需要了解它才能使用它。
||
and &&
.&&
operator will run first than ||
.
&&
operator will, first, verify the left condition. There's no need to check two of them, to &&
return true, if the first one is true, then he can check the second.
||
operator will execute right after &&
. It will verify if the two conditions return false, for this reason he needs to verify both.
()
. To do it in the way you need, use ()
to present a new rule to your if statement:if ( (x.contains("this") || x.contains("that")) && y.contains("something else")!= true)