A precedência / prioridade do operador de seta (->) é mais baixa ou a prioridade de atribuição / atribuição combinada é mais baixa?

18

JLS :

O operador de precedência mais baixa é a seta de uma expressão lambda (->) , seguida pelos operadores de atribuição.

Seguido em que direção (prioridade crescente, prioridade decrescente)? - "seguido" significa que a atribuição tem prioridade mais alta ou mais baixa (em relação ao operador de seta)? Eu acho que, aumentando, porque "mais baixo" (para seta) significa absolutamente mais baixo.

Pelo que entendi, a seta (->) deve estar na parte inferior desta tabela de precedência do operador de Princeton (que está abaixo de todos os operadores de atribuição), portanto, a seta (->) possui 0 (zero) nível de prioridade (conforme essa tabela).

Estou correto no meu entendimento?

O ExamTray parece dizer que a prioridade da seta é pelo menos igual à atribuição ... Além disso, esclareceu que a associatividade da seta é Esquerda-> Para-> Direita (ao contrário da atribuição). Não encontrei nenhuma cotação JLS para associatividade de flechas.

Eu sempre pensava que a prioridade da atribuição é principalmente a mais baixa por um motivo.

Código completo
fonte
5
The lowest precedence operator is the arrow of a lambda expression.
21419 Kayaman
2
Sim, seu entendimento está correto.
Eran
4
Se ->é o baixo est , operadores de atribuição não pode ter baixa er precedência.
Andy Turner
IntFunction fo = a->b->a-b; // in test Implica prioridade / associatividade de -> em geral. Por isso, decidi esclarecer -> lugar de precedência / associatividade em toda a tabela de precedência / associatividade porque me sentia insegura.
Code Complete
11
@glglgl seu exemplo IntUnaryOperator op; op = x -> x;é interessante. Talvez (op = x) -> xnão seja considerado porque op = xnão é uma instância válida da LambdaParametersprodução?
Andy Turner

Respostas:

13

Observe a frase que precede o texto JLS citado :

A precedência entre os operadores é gerenciada por uma hierarquia de produções gramaticais.

A gramática da linguagem Java determina quais construções são possíveis e implicitamente, a precedência do operador.

Até a tabela de princeton que você vinculou afirma:

Não há tabela de precedência explícita do operador na Especificação de Linguagem Java. Tabelas diferentes na web e em livros didáticos discordam em alguns aspectos menores.

Portanto, a gramática da linguagem Java não permite expressões lambda à esquerda de um operador de atribuição e, da mesma forma, não permite atribuições à esquerda da ->. Portanto, não há ambiguidade possível entre esses operadores e a regra de precedência, embora explicitamente declarada no JLS, fica sem sentido.

Isso permite compilar, por exemplo, uma jóia, sem ambiguidade:

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

Primeiro, vamos explicar a questão prática aqui.

Supondo que você tenha uma definição como

IntUnaryOperator op;

O seguinte é aceito sintaticamente e funciona conforme o esperado:

op = x -> x;

Ou seja, temos uma função de identidade intatribuída à opvariável. Mas se =tivesse uma prioridade mais alta, esperamos que o Java interprete isso como

(op = x) -> x;

O que não é sintaticamente válido, portanto, deve ser um erro de compilação. Portanto, na prática, a atribuição não tem maior precedência que a flecha.

Mas o seguinte também está OK (suponha que tseja uma variável de classe / instância do tipo int):

op = x -> t = x;

Isso compila e a função, se aplicada, atribui o valor do operando te também o retorna.

Isso significa que a seta não tem precedência mais alta que a atribuição t = x. Caso contrário, teria sido interpretado como

op = ( x -> t ) = x

e claramente, não é isso que acontece.

Portanto, parece que as operações têm igual precedência. Além do mais, eles são associativos. Isso está implícito na gramática do capítulo 19 da JLS :

Expression:
  LambdaExpression
  AssignmentExpression

LambdaExpression:
  LambdaParameters -> LambdaBody

...

LambdaBody:
  Expression
  Block

Portanto, o lado direito do corpo lambda nos leva de volta Expression, o que significa que podemos ter um lambda (prioridade mais alta) dentro dele ou uma atribuição (prioridade mais alta) nele. O que quero dizer com "prioridade mais alta" é que, quanto mais aprofundadas as regras de produção, mais cedo a expressão será avaliada.

O mesmo vale para o operador de atribuição:

AssignmentExpression:
  ConditionalExpression
  Assignment

Assignment:
  LeftHandSide AssignmentOperator Expression

Mais uma vez, o lado direito da tarefa nos leva de volta para Expression, para que possamos ter uma expressão lambda ou uma tarefa lá.

Portanto, em vez de confiar no texto da JLS, a gramática nos fornece uma descrição bem definida da situação.

RealSkeptic
fonte