箭头(->)运算符 precedence/priority 是最低的,还是 assignment/combined 赋值的优先级最低?

Arrow (->) operator precedence/priority is lowest, or priority of assignment/combined assignment is lowest?

JLS:

The lowest precedence operator is the arrow of a lambda expression (->), followed by the assignment operators.

遵循哪个方向(增加优先级,降低优先级)? - "followed" 表示赋值具有更高的优先级或更低的优先级(相对于箭头运算符)?我猜,在增加,因为 "lowest" (对于箭头)意味着绝对最低。

据我了解,箭头 (->) 应该位于此 Princeton 运算符优先级 table 的最底部(即低于所有赋值运算符),因此箭头 (->) 具有0(零)优先级(根据 table)。

我的理解正确吗?

ExamTray 似乎说箭头优先级至少与赋值相同...另外澄清箭头关联性是左->到->右(与赋值不同)。我没有找到任何关于箭头关联性的 JLS 引用。

我一直认为分配优先级原则上是最低的,这是有原因的。

首先,让我们在这里解释一下实际问题。

假设您的定义类似于

IntUnaryOperator op;

以下语法被接受,并按预期工作:

op = x -> x;

也就是说,我们在 int 上有一个恒等函数分配给 op 变量。但是,如果 = 具有更高的优先级,我们希望 Java 将其解释为

(op = x) -> x;

这在语法上无效,因此应该是编译错误。因此,在实践中,赋值并不比箭头具有更高的优先级。

但是下面这样也行(假设t是一个class/instance类型的int变量):

op = x -> t = x;

这会编译,并且函数(如果应用)会将操作数的值分配给 t 以及 returns 它。

这意味着箭头的优先级不高于赋值 t = x。否则它会被解释为

op = ( x -> t ) = x

很明显,事实并非如此。

所以看起来这些操作具有相同的优先级。更重要的是,它们是右结合的。 JLS chapter 19:

处的语法暗示了这一点
Expression:
  LambdaExpression
  AssignmentExpression

LambdaExpression:
  LambdaParameters -> LambdaBody

...

LambdaBody:
  Expression
  Block

所以 lambda 主体的右侧让我们回到 Expression,这意味着我们可以在其中有一个(更高优先级)lambda,或者在其中有一个(更高优先级)赋值。我所说的 "higher priority" 的意思是,您对产生式规则的了解越深,表达式的计算就越早。

赋值运算符也是如此:

AssignmentExpression:
  ConditionalExpression
  Assignment

Assignment:
  LeftHandSide AssignmentOperator Expression

再一次,赋值的右边把我们带回到 Expression,所以我们可以在那里有一个 lambda 表达式或赋值。

因此,语法为我们提供了对情况的明确描述,而不是依赖于 JLS 文本。

注意引用 JLS text 之前的句子:

Precedence among operators is managed by a hierarchy of grammar productions.

Java 语言的语法决定了哪些结构是可能的,并且隐含地决定了运算符的优先级。

即使是您链接的 princeton table 状态:

There is no explicit operator precedence table in the Java Language Specification. Different tables on the web and in textbooks disagree in some minor ways.

因此,Java 语言的语法不允许在赋值运算符左侧使用 lambda 表达式,同样,也不允许在 -> 左侧进行赋值。因此,这些运算符之间没有歧义,优先规则虽然在 JLS 中明确说明,但变得毫无意义。

这允许编译,例如这样的gem,没有歧义:

static Consumer<String> C;
static String S;
public static void main(String[] args)
{
  Runnable r;
  r = () -> C = s -> S = s;
}