Abd*_*ane 7 java operator-precedence java-7
我测试的优先级&&,并||和我有令人困惑的例子.在Java中,&&运算符优先级高于运算符||.
所以,如果我们有这3个表达式:
//expr1 = true , expr2 = false; expr3 = false;
if(expr1 || expr2 && expr3);
Run Code Online (Sandbox Code Playgroud)
应评估为:
if(expr1 || (expr2 && expr3));
Run Code Online (Sandbox Code Playgroud)
所以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);
Run Code Online (Sandbox Code Playgroud)
输出:
true
10
20
Run Code Online (Sandbox Code Playgroud)
这证明只有 a1 < a2被评估.你能解释为什么会这样吗?
Li3*_*357 13
表达是短路的.从链接:
当AND函数的第一个参数求值为false时,整数值必须为false; 当OR函数的第一个参数的计算结果为true时,整数值必须为true.
它看到其余的条件无关紧要,因为其中一个操作数||已经为真(10 <20).如果其中一个操作数为真,则无论其余条件是什么,都是如此.
您可以按位使用&并|防止这种情况发生.
但是,(expr2 && expr3)应该在expr1之前评估,不是吗?
不可以.您必须将优先级和评估顺序的概念分开.
优先级:指示表达式的括号,而不是表达式的计算顺序.举个例子:
true || false && false
Run Code Online (Sandbox Code Playgroud)
括号括起来因为&&优先级高于||:
true || (false && false)
Run Code Online (Sandbox Code Playgroud)
这并不意味着在Java的情况下首先评估括号中的内容.优先级只是阐明什么操作的操作数是,在这种情况下false和false,其中在这种情况下:
(true || false) && (false || false)
Run Code Online (Sandbox Code Playgroud)
&&是true和的操作数,而false不是false和false.
评估顺序:描述每个操作数的评估顺序和运算符的应用顺序,有时是语言特定的.这决定了如何评估表达式,与优先级不同.
在这种情况下,您的示例:
true || false && false
Run Code Online (Sandbox Code Playgroud)
如前所述,由于优先权而成为此:
true || (false && false)
Run Code Online (Sandbox Code Playgroud)
但是,与C++,JavaScript或许多其他语言不同,Java具有严格的从左到右的评估.根据Java语言规范:
15.7.评估订单
Java编程语言保证运算符的操作数似乎以特定的评估顺序进行评估,即从左到右.
15.7.1.首先评估左手操作数
在评估右侧操作数的任何部分之前,似乎完全评估了二元运算符的左侧操作数.
所以,当你有:
true || (false && false)
Run Code Online (Sandbox Code Playgroud)
Java 首先评估左操作数,结果证明是true.然后整个条件短路.||括号中的右操作数永远不会被评估.你的另一个例子也是如此:
a1 < a2 || (++a1 > a2 && ++a2 < a1)
^^^^^^^^^^^^^^^^^^^^^^^^
Step 0, precedence and parenthesization
Run Code Online (Sandbox Code Playgroud)
a1 < a2 || (++a1 > a2 && ++a2 < a1)
^^^^^^^
Step 1, left operand evaluated, variables resolved to values 10 and 20, condition is true
Run Code Online (Sandbox Code Playgroud)
true || (++a1 > a2 && ++a2 < a1)
^^^^
Step 2, short circuits, left operand is not evaluated
Run Code Online (Sandbox Code Playgroud)
再举一个更复杂的例子:
false || false || true && (false || true) || false
Run Code Online (Sandbox Code Playgroud)
由于优先权,它变为:
false || false || (true && (false || true)) || false
Run Code Online (Sandbox Code Playgroud)
然后,评估从左到右开始:
false || false || (true && (false || true)) || false
^^^^^^^^^^^^^^
Step 1, false || false, does not short circuit, right operand is evaluated, is false
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
true || false
^^^^
Step 3, true || false short circuits, right operand is not evaluated, is true
Run Code Online (Sandbox Code Playgroud)
因此整个表达式评估为true.整个表达从整个过程中从左到右进行评估.优先级仅通过括号而不是评估顺序来指定运算符的操作数.
进一步阅读Eric Lippert关于优先级与关联性与评估顺序的解释性文章,如Daniel Pryden所述,它清除了很多混乱.
主要的一点是,优先级并不决定表达式的评估.它只规定表达式应如何括起来.另一方面,评估顺序告诉我们如何评估表达式,并且在Java的情况下总是从左到右.
第一行打印true是因为||操作员短路.
a1 < a2是的,因此不需要计算布尔表达式的其余部分并true返回.
应该在expr1之前评估expr2
是不正确的,因为运算符优先级会影响表达式的结构,而不会影响评估顺序(在大多数情况下).如果你要对表达式进行重新排序(expr2 && expr3) || expr1,那么是的,expr2之前会进行评估expr1
优先级:
boolean result = a || b && c
Run Code Online (Sandbox Code Playgroud)
为了根据优先级规则获得正确的值,编译器必须在逻辑上将其评估为:
boolean x = b && c
boolean result = a || x
Run Code Online (Sandbox Code Playgroud)
这说明了b && c在计算之前必须进行评估的观点result.但是,在布尔代数中,可以编写其结果不依赖于所有操作数的表达式.利用这一事实来实现称为短路的编译器优化.
短路:
对于任何布尔表达式:
a || b
Run Code Online (Sandbox Code Playgroud)
结果不依赖于b是否a评估true.如果a是true,如果没有关系b计算结果为真或假.因此,编译器执行:
a || b && c
Run Code Online (Sandbox Code Playgroud)
好像它已被写入:
boolean result = a;
if (!a) result = b && c;
Run Code Online (Sandbox Code Playgroud)
请注意,以这种方式执行,仍然遵守优先规则.表达式未评估为(a || b) && c.由于表达的整体结果并不取决于(b && c)在该情况下a是真实的,b && c简直是永远不会计算.
这是一件好事.当一个操作数的正确性取决于另一个操作数的正确性时,短路允许您编写正确的程序.例如:
if (myString == null || !myString.isEmpty() && myString != "break") return;
Run Code Online (Sandbox Code Playgroud)
没有短路评估,布尔表达式可以抛出一个NullPointerException.但是,由于短路评估,这个表达式,如所写,永远不会抛出NullPointerException.
短路也可以用作性能优化.如果评估一个操作数非常昂贵,那么首先评估另一个操作数可以节省评估操作数所需的执行时间,该操作数的值不会影响整个表达式的最终结果.
| 归档时间: |
|
| 查看次数: |
643 次 |
| 最近记录: |