我正在测试 &&
之间的优先级和 ||
我有一个令人困惑的例子。在 Java 中,&&
运算符优先级高于运算符 ||
.
所以如果我们有这 3 个表达式:
//expr1 = true , expr2 = false; expr3 = false;
if(expr1 || expr2 && expr3);
它应该被评估为:
if(expr1 || (expr2 && expr3));
所以 expr2 && expr3
应该在 expr1
之前评估.然而,这个例子:
int a1 = 10;
int a2 = 20;
System.out.println(a1 < a2 || ++a1 > a2 && ++a2 < a1);
System.out.println(a1);
System.out.println(a2);
输出:
true
10
20
这证明只有a1 < a2
被评估。
您能解释一下为什么会这样吗?
最佳答案
表达式是short-circuiting .来自链接:
when the first argument of the AND function evaluates to false, the overall value must be false; and when the first argument of the OR function evaluates to true, the overall value must be true.
它看到条件的其余部分无关紧要,因为 ||
的操作数之一已经为真 (10 < 20)。如果其中一个操作数为真,那么无论其余条件是什么,它都为真。
您可以使用按位 &
和 |
来防止这种情况。
But, the ( expr2 && expr3 ) should be evaluated before expr1, no ?
没有。您必须将优先级 和评估顺序 的概念分开。
优先级:指示表达式的括号,而不是表达式计算的顺序。例如:
true || false && false
因为
&&
比||
有更高的优先级,所以用括号括起来:true || (false && false)
这并不意味着括号中的内容在 Java 的情况下首先被评估。优先级只是阐明运算符的操作数是什么,在本例中为
false
和false
,而在this 中:(true || false) && (false || false)
&&
的操作数是true
和false
,而不是false
和false
.求值顺序:描述每个操作数的求值顺序和运算符的应用顺序,有时是特定于语言的。与优先级不同,这决定了表达式的计算方式。
在这种情况下,您的示例:
true || false && false
如前所述,由于优先级而变成这样:
true || (false && false)
但 Java 与 C++、JavaScript 或许多其他语言不同,它具有严格的从左到右的计算方式。根据 Java Language Specification :
15.7. Evaluation Order
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.
15.7.1. Evaluate Left-Hand Operand First
The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.
所以,当你有:
true || (false && false)
Java 首先计算左操作数,结果为 true
。然后整个状态短路。括号中 ||
的右操作数根本不会被求值。您的另一个示例也是如此:
a1 < a2 || (++a1 > a2 && ++a2 < a1)
^^^^^^^^^^^^^^^^^^^^^^^^
Step 0, precedence and parenthesization
a1 < a2 || (++a1 > a2 && ++a2 < a1)
^^^^^^^
Step 1, left operand evaluated, variables resolved to values 10 and 20, condition is true
true || (++a1 > a2 && ++a2 < a1)
^^^^
Step 2, short circuits, left operand is not evaluated
再举一个更复杂的例子:
false || false || true && (false || true) || false
由于优先级,它变成:
false || false || (true && (false || true)) || false
然后,评估开始,从左到右:
false || false || (true && (false || true)) || false
^^^^^^^^^^^^^^
Step 1, false || false, does not short circuit, right operand is evaluated, is false
false || (true && (false || true)) || false
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Step 2, false || (true && (false || true)), does not short circuit, right operand is evaluated
Step 2A, (true && (false || true)), does not short circuit, right operand is evaluated
Step 2B, (false || true), does not short circuit, right operand is evaluated, is true
Step 2C, (true && true), does not short circuit, right operand is evaluated, is true
Step 2D, false || true, does not short circuit, right operand is evaluated, is true
true || false
^^^^
Step 3, true || false short circuits, right operand is not evaluated, is true
因此整个表达式的计算结果为 true
。整个表达式从左到右进行评估。优先级仅通过括号指定运算符的操作数,而不是计算顺序。
进一步阅读 Eric Lippert's explanatory article关于 Daniel Pryden 提到的优先级与关联性与评估顺序,它消除了很多困惑。
主要的收获是优先级并不决定对表达式求值的内容。它只规定了表达式应该如何括起来。另一方面,求值顺序告诉我们表达式是如何求值的,在 Java 中总是从左到右。
关于java - 关于 '&&' 和 '||' 优先级的混淆示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40071805/