Java表达式的顺序、运算符优先级和结合性之间的差异

huangapple go评论145阅读模式
英文:

Differences between Java order of expression, operator precedence and associativity

问题

我遇到了这个考试题目。

考试题目:以下代码片段的结果是什么?

3: var tiger = "Tiger";
4: var lion = "Lion";
5: final var statement = 250 > 338 ? lion : tiger = " is Bigger";
6: System.out.println(statement);

正确答案是

F. 该代码由于第5行而无法编译

解释如下:

  1. 该代码无法编译,因为赋值运算符在此表达式中具有最高的优先级。
  2. 三元运算符的两侧必须具有相同的类型。这个表达式无效,因为第二个赋值运算符的左侧不是一个变量,所以答案是选项F。
  3. 请注意,如果问题在表达式(Tiger = " is Bigger")周围添加了明确的括号,选项E将具有正确的输出。

当我自己运行代码时,我得到了编译错误:

test.java:11: error: unexpected type
final var statement = 250 > 338 ? lion : tiger = " is Bigger";
                                ^
  required: variable
  found:    value
1 error
error: compilation failed

在寻求第二意见、阅读JLS第15节和以下其他SO问题之后:

https://stackoverflow.com/questions/6800590/what-are-the-rules-for-evaluation-order-in-java

https://stackoverflow.com/questions/28219423/if-parenthesis-has-a-higher-precedence-then-why-is-increment-operator-solved-fir

我提出了一些理论:

  1. 表达式评估顺序、操作符优先级和结合性是不同的概念。
  2. 表达式评估尊重括号和操作符优先级,符合JLS 15.7.3的规定。
  3. 所有表达式评估都是从左到右进行的。
  4. 操作符优先级确定了表达式的分组。
  5. 结合性仅适用于相同的操作符,并确定使用相同操作符的表达式的执行顺序。
  6. Java在编译时检查有效的表达式,从左到右进行检查,尊重括号和操作符的优先级。
  7. 对于带有操作符的表达式,它以不同的方式对操作数进行检查,具体取决于操作符。

有了这些新知识,我现在会尝试解释为什么第5行无法编译:

  1. Java从左到右开始检查有效的表达式,使用表达式评估顺序。
  2. Java找到了第一个赋值运算符(最左侧的)。
  3. 由于赋值运算符“=”具有从右到左的结合性,Java会检查右侧是否有其他赋值运算符,并开始评估最右侧的赋值运算符。
  4. 它找到了一个“=”,然后检查右侧是否有其他“=”。
  5. 它找不到其他“=”,所以开始评估此最右侧的“=”的操作数。
  6. 根据15.26,Java检查前一个“=”和此“=”之间的所有内容是否仅为一个变量。
  7. 它找到了表达式250 > 338 ? lion : tiger,这是一个有效的表达式,但是这个表达式的结果是一个值。
  8. Java只允许在赋值运算符的左侧使用变量,因此无法编译。

现在我会尝试使用相同的理论来解释此代码的正确情况:final var statement = 250 > 338 ? lion : (tiger = " is Bigger");

  1. Java从左到右开始检查有效的表达式,使用表达式评估顺序。
  2. Java在同一“范围内”找不到其他赋值运算符“=”。
  3. 根据15.26,Java检查这个“=”的左操作数是否为变量。通过。
  4. 然后它评估右操作数是否为一个有效的表达式,返回一个可分配给左操作数的值。

考试提供的解释是否有问题,或者我是否仍然不理解为什么此代码无法编译?

  1. 他们声称赋值运算符“=”在此表达式中具有最高的优先级。根据此操作符优先级表,http://www.cs.bilkent.edu.tr/~guvenir/courses/CS101/op_precedence.html,赋值运算符的优先级最低。
  2. 他们混淆了操作符优先级和表达式评估顺序,而没有将这两个概念区分开来?
英文:

I came across this question on an exam.

Exam question: What is the result of the following code snippet?

3: var tiger = "Tiger";
4: var lion = "Lion";
5: final var statement = 250 > 338 ? lion : tiger = " is Bigger";
6: System.out.println(statement);

The correct answer was
> F. The code will not compile because of line 5

The explanation is:
> 1. The code does not compile because the assignment operator has the highest order of precedence in this expression.
> 2. Both sides of the ternary operator must have the same type. This expression is invalid, as the left side of the second assignment
> operator is not a variable, so the answer is option F.
> 3. Note that if the question had added explicit parentheses around the expression (Tiger = " is Bigger"), option E would have the correct
> output.

When I ran the code myself, I got a compilation error:

test.java:11: error: unexpected type
final var statement = 250 > 338 ? lion : tiger = " is Bigger";
                                ^
  required: variable
  found:    value
1 error
error: compilation failed

After asking for second opinions, reading JLS section 15, and these other SO questions:

<https://stackoverflow.com/questions/6800590/what-are-the-rules-for-evaluation-order-in-java>

<https://stackoverflow.com/questions/28219423/if-parenthesis-has-a-higher-precedence-then-why-is-increment-operator-solved-fir>

I came up with a few theories:

  1. Order of expression evaluation, operator precedence, and associativity are different concepts.
  2. Expression evaluation respects parentheses and operator precedence, per JLS 15.7.3.
  3. All expression evaluations are made from left to right.
  4. Operator precedence determines grouping of expressions.
  5. Associativity only applies to the same operator and determines the execution order of the expressions using the same operator.
  6. Java checks for valid expressions at compile time, from left to right, respecting parenthesis and operator precedence.
  7. For expressions with operators, it performs this check on the operands in different ways depending on the operator.

With the new knowledge, I will now try to explain why line #5 fail to compile:

  1. Java starts checking for valid expressions, using order of expression evaluation, from left to right.
  2. Java finds the first assignment operator (left-most).
  3. Since assignment operator "=" has Right-To-Left associativity, Java checks if there are any other assignment operator on the right side and start the evaluation of the more-right assignment operator.
  4. It finds one "=", it checks for any other "=" on right side.
  5. I finds no other "=", so it starts to evaluate the operands of this right-most "=".
  6. Per 15.26, Java checks if everything between the previous "=" and this "=" is only a variable.
  7. It finds the expression 250 &gt; 338 ? lion : tiger, which is a valid expression, but this expression evaluates to a value.
  8. Java only allows variable on the left side of the assignment operator, so it fails to compile.

Now I would try to apply this same theory to explain the correct scenario of this code: final var statement = 250 &gt; 338 ? lion : (tiger = &quot; is Bigger&quot;);

  1. Java starts checking for valid expressions, using order of expression evaluation, from left to right.
  2. Java does not find any other assignment operator "=" in the same "scope".
  3. Per 15.26, Java checks if the left operand of this "=" is a variable. Passed.
  4. Then it evaluates whether the right operand is a valid expression that returns a value that is assignable to the left operand.

Has the explanation provided by the exam dropped the ball or do I still not understanding how this code did not compile?

  1. They stated that the assignment operator "=" somehow has the highest order of precedence in this expression. Based on this operator precedence table, <http://www.cs.bilkent.edu.tr/~guvenir/courses/CS101/op_precedence.html>, assignment operator has the lowest precedence.
  2. They used operator precedence interchangeably with order of evaluation expression instead of separating the two concepts?

答案1

得分: 1

你说得对,他们说错了,赋值操作符的优先级是最低的。

你说错了,他们从未在任何地方提到“评估顺序”(至少在你展示的内容中没有)。所示代码中没有任何需要考虑评估顺序的地方。赋值与评估顺序无关。

  1. 该代码不编译,因为在此表达式中赋值操作符具有最高的优先级。

运算符优先级 如下所示:

9   >   relational(关系运算)
2   ?:  ternary(三元运算)
1   =   assignment(赋值)

这意味着要明确使用括号显示优先级,语句变为:

statement = ((250 > 338) ? lion : tiger) = " is Bigger";
  1. 三元操作符的两侧必须具有相同的类型。此表达式无效,因为第二个赋值操作符的左侧不是一个变量,所以答案是选项 F。

三元操作符是 ((250 > 338) ? lion : tiger),"both sides" 指的是两个赋值操作符。

正如它所说,"此表达式无效,因为第二个赋值操作符的左侧不是一个变量"。

  1. 请注意,如果问题在表达式周围添加了明确的括号(Tiger = " is Bigger"),选项 E 将有正确的输出。

你已经自己确认了这一点。

要明确使用括号显示优先级,语句变为:

statement = ( (250 > 338) ? lion : (tiger = " is Bigger") );
英文:

You are correct, they misspoke, assignment operator has the lowest order of precedence.

You are incorrect, they never mention "order of evaluation" anywhere (that you've shown, anyway). The code shown doesn't do anything where order of evaluation matters. The assignment has nothing to with order of evaluation.



> 1. The code does not compile because the assignment operator has the highest order of precedence in this expression.

Operator precedence shows:

9   &gt;   relational
2   ?:  ternary
1   =   assignment

Which means that to explicitly show precedence using parenthesis, the statement becomes:

statement = ((250 &gt; 338) ? lion : tiger) = &quot; is Bigger&quot;;

> 2. Both sides of the ternary operator must have the same type. This expression is invalid, as the left side of the second assignment operator is not a variable, so the answer is option F.

The ternary operator being ((250 &gt; 338) ? lion : tiger), "both sides" refer to the two assignment operators.

As it says, "This expression is invalid, as the left side of the second assignment operator is not a variable".


> 3. Note that if the question had added explicit parentheses around the expression (Tiger = " is Bigger"), option E would have the correct output.

You already confirmed that yourself.

To explicitly show precedence using parenthesis, the statement becomes:

statement = ( (250 &gt; 338) ? lion : (tiger = &quot; is Bigger&quot;) );

huangapple
  • 本文由 发表于 2020年8月14日 08:52:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/63405066.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定