参考:java - 关于 '&&'和 '||'优先级的令人困惑的示例
首先,程序中的优先级和执行顺序是两个不同的概念。
代码示例
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
进行了评估。
解释
我们知道Java中&&
的优先级高于||
,所以
true || false && false
在Java中相当于:
true || (false && false)
但是,这并不意味着程序会先执行括号中的内容。
由于Java语言的执行顺序是从左到右,所以如果上述的布尔值是表达式的话,则会先计算左边表达式的内容,这叫执行顺序(或评估顺序)。
执行顺序是特定于语言的,Java与C++,JavaScript或许多其他语言不同,它具有严格的从左到右的评估。
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.
影响
执行顺序对程序是有影响的。
程序设计中有个名词叫短路求值[short-circuiting],是一种逻辑运算符的求值策略。意思是:只有当第一个运算数的值无法确定逻辑运算的结果时,才对第二个运算数进行求值。
例如,当AND的第一个运算数的值为false时,其结果必定为false;当OR的第一个运算数为true时,最后结果必定为true,在这种情况下,就不需要知道第二个运算数的具体值。
在一些语言中(如Lisp),默认的逻辑运算符就是短路运算符,而在另一些语言中(如Java,Ada),短路和非短路的运算符都存在。
Java中&&和||就是短路求值的运算;而&和|就是非短路求值的运算了。
题目解释
最后回到一开始的这个题目:
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
之所以程序只对a1 < a2
进行了评估,是因为程序发现a1 < a2
等于true之后,后面的值可以不用算了
true || (++a1 > a2 && ++a2 < a1)
^^^^
Step 2, short circuits, left operand is not evaluated
所以后面的++a1
和++a2
都不会被执行。
结论
主要结论是,优先级并不决定表达式的计算方式。它仅指示如何对表达式加上括号。另一方面,求值顺序可以准确地告诉我们表达式的求值方式,在Java中,总是从左到右。
网友评论