表达式正在进行“短路计算”。来自链接:
https://en.m.wikipedia.org/wiki/Short-circuit_evaluation
当AND函数的第一个参数计算结果为false时,整个表达式的值必须为false;当OR函数的第一个参数计算结果为true时,整个表达式的值必须为true。
它发现条件的其余部分并不重要,因为||的操作数之一已经是true(10 < 20)。如果其中一个操作数为true,则无论条件的其余部分如何,它都是true。
你可以使用按位运算符&和|来防止这种情况。
但是,(expr2 && expr3)不应该在expr1之前计算吗?
不。您必须区分“优先级”和“计算顺序”的概念。
优先级:规定了表达式的括号顺序,而不是表达式求值的顺序。例如:
true || false && false
因为 &&
的优先级高于 ||
,所以加括号:
true || (false && false)
这并不意味着在 Java 的情况下括号中的内容会首先被评估。优先级只是澄清运算符的操作数,本例中为false
和false
,而在这种情况下:
这并不意味着在 Java 中,括号内的表达式会首先被计算。优先级只是澄清操作符的操作数,即在本例中为false
和false
,而在这种情况下:
(true || false) && (false || false)
&&
运算符的操作数是 true
和 false
,而不是 false
和 false
。
求值顺序: 描述每个操作数被求值和运算符被应用的顺序,有时是语言特定的。这决定了表达式的求值顺序,与优先级不同。
在本例中,您的示例:
true || false && false
正如前面所述,这是由于优先级而发生的:
true || (false && false)
但是,与C++、JavaScript或其他许多语言不同,Java有严格的从左到右的求值顺序。根据Java语言规范:
15.7.求值顺序
Java编程语言保证运算符的操作数会按照特定的顺序进行求值,即从左到右。
15.7.1.先评估左侧操作数
一个二元操作符的左侧操作数在右侧任何部分被评估之前应该完全被评估。
因此,当你有:
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解释性文章关于优先级与结合性与评估顺序,正如Daniel Pryden所提到的,这消除了很多困惑。
主要的要点是,优先级并不决定表达式的评估方式。它只规定了如何将表达式括起来。另一方面,评估顺序告诉我们表达式的确切评估方式,在Java的情况下始终从左到右。
expr2
和expr3
被它所分组,但是它们仍然从左到右被求值。 - Peter Lawrey