我正在测试 throw er; // Unhandled stream error in pipe.
^
Error: EMFILE: too many open files, open 'C:\Users\Administrator\Desktop\graby\image.jpg'
at Error (native)
[nodemon] app crashed - waiting for file changes before starting...
和&&
之间的优先级,我有一个令人困惑的例子。在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
。
你能解释为什么会这样吗?
答案 0 :(得分:13)
表达式为short-circuiting。从链接:
当AND函数的第一个参数求值为false时,整数值必须为false;当OR函数的第一个参数的计算结果为true时,整数值必须为true。
它发现其余条件并不重要,因为||
的一个操作数已经为真(10 <20)。如果其中一个操作数是真的,那么无论其他条件是什么,它都是真的。
您可以使用按位&
和|
来阻止此操作。
但是,(expr2&amp;&amp; expr3)应该在expr1之前评估,不是吗?
没有。您必须将优先级和评估顺序的概念分开。
优先级:指示表达式的括号,而不是表达式的计算顺序。举个例子:
true || false && false
为括号加以括号,因为&&
的优先级高于||
:
true || (false && false)
这并不意味着在Java的案例中首先评估括号中的内容。优先级只是澄清运算符的操作数,在本例中为false
和false
,其中 this 情况:
(true || false) && (false || false)
&&
的操作数为true
和false
,而不是false
和false
。
评估顺序:描述评估每个操作数的顺序和应用运算符,有时是特定于语言的。这决定了如何评估表达式,与优先级不同。
在这种情况下,您的示例:
true || false && false
如前所述,由于优先权而成为此:
true || (false && false)
但是,与C ++,JavaScript或许多其他语言不同,Java具有严格的从左到右的评估。根据{{3}}:
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
。整个表达从整个过程中从左到右进行评估。优先级仅通过括号而不是评估顺序来决定运算符的操作数。
Java Language Specification进一步阅读Eric Lippert's explanatory article关于优先级与关联性与评估顺序之间的关联Daniel Pryden,它清除了很多混乱。
主要内容是优先级并不表示评估表达式的内容。它只规定表达式应如何括起来。另一方面,评估顺序告诉我们如何评估表达式,并且在Java的情况下始终从左到右。
答案 1 :(得分:6)
由于||
运算符短路,第一行打印a1 < a2
。
true
为true,因此不需要评估布尔表达式的其余部分并返回(expr2 && expr3) || expr1
。
应在expr1 之前评估expr2
不正确,因为运算符优先级会影响表达式的结构,而不会影响评估顺序(在大多数情况下)。如果您要重新排序表达式以使其为expr2
,那么是,expr1
将在class Obj {
private:
int num;
public:
Obj();
void setNum(int nuovo_num);
int getNum();
};
答案 2 :(得分:5)
<强>优先级:强>
boolean result = a || b && c
为了根据优先级规则获得正确的值,编译器必须在逻辑上将其评估为:
boolean x = b && c
boolean result = a || x
这说明在b && c
可以计算之前必须先评估result
。但是,在布尔代数中,可以编写结果不依赖于所有操作数的表达式。利用这一事实来启用称为短路的编译器优化。
短路:
对于任何布尔表达式:
a || b
如果b
评估为a
,则结果不依赖于true
。当a
为true
时,b
评估为true或false无关紧要。因此,编译器执行:
a || b && c
好像已经写好了:
boolean result = a;
if (!a) result = b && c;
请注意,以这种方式执行,仍然遵守优先规则。表达式未计算为(a || b) && c
。由于在(b && c)
为真的情况下,表达式的整体结果不依赖a
,因此b && c
永远不会被评估。
这是一件好事。当一个操作数的正确性取决于另一个操作数的正确性时,短路允许您编写正确的程序。例如:
if (myString == null || !myString.isEmpty() && myString != "break") return;
如果没有短路评估,布尔表达式可能会抛出NullPointerException
。但是,由于短路评估,所写的表达式永远不会抛出NullPointerException
。
短路也可用作性能优化。如果评估一个操作数非常昂贵,那么首先评估另一个操作数可以节省评估操作数所需的执行时间,该操作数的值不会影响整个表达式的最终结果。
答案 3 :(得分:3)
即使您在
中使用明确的括号if (expr1 || (expr2 && expr3))
首先评估 expr1
,因为运算符的操作数是从左到右计算的。由于||
是一个短路运算符,因此只有当(expr2 && expr3)
为expr1
时,才会评估第二个操作数(在您的情况下为false
)。
删除括号后,如果expr1
为false,则运算符优先级才会起作用。在这种情况下,&&
操作数将在||
运算符之前进行求值,其值将是||
运算符的第二个操作数。