La freccia (->) la precedenza / priorità dell'operatore è più bassa o la priorità di assegnazione / assegnazione combinata è più bassa?


18

JLS :

L' operatore con precedenza più bassa è la freccia di un'espressione lambda (->) , seguita dagli operatori di assegnazione.

Seguito in quale direzione (priorità crescente, priorità decrescente)? - "seguito" significa che l'assegnazione ha priorità o priorità inferiore (rispetto all'operatore freccia)? Immagino, in aumento, perché "più basso" (per freccia) significa assolutamente più basso.

A quanto ho capito, la freccia (->) dovrebbe trovarsi in fondo a questa tabella di precedenza degli operatori di Princeton (che è al di sotto di tutti gli operatori di assegnazione), quindi la freccia (->) con livello di priorità 0 (zero) (come da quella tabella).

Sono corretto nella mia comprensione?

ExamTray sembra dire che la priorità della freccia è almeno uguale all'assegnazione ... Inoltre ha chiarito che l'associatività della freccia è Sinistra-> A-> Destra (diversamente dall'assegnazione). Non ho trovato alcuna citazione JLS per l'associatività delle frecce.

Ho sempre pensato che la priorità di assegnazione fosse principalmente più bassa per un motivo.


5
The lowest precedence operator is the arrow of a lambda expression.
Kayaman,

2
Sì, la tua comprensione è corretta.
Eran,

4
Se ->è la bassa est , operatori di assegnazione non possono avere bassa er la precedenza.
Andy Turner,

IntFunction fo = a->b->a-b; // in test Implica priorità / associatività di -> in generale. Così ho deciso di chiarire -> il posto di precedenza / associatività nell'intera tabella di precedenza / associatività perché non ne ero sicuro.
Codice completato il

1
@glglgl il tuo esempio di IntUnaryOperator op; op = x -> x;è interessante. Forse (op = x) -> xnon è considerato perché op = xnon è un'istanza valida della LambdaParametersproduzione?
Andy Turner,

Risposte:


13

Nota la frase che precede il testo JLS citato :

La precedenza tra gli operatori è gestita da una gerarchia di produzioni grammaticali.

La grammatica del linguaggio Java determina quali costrutti sono possibili e implicitamente, la precedenza dell'operatore.

Anche la tabella princeton che hai collegato afferma:

Non esiste una tabella di precedenza esplicita dell'operatore nella specifica del linguaggio Java. Diverse tabelle sul Web e nei libri di testo non sono d'accordo in alcuni modi minori.

Quindi, la grammatica del linguaggio Java non consente espressioni lambda a sinistra di un operatore di assegnazione e, allo stesso modo, non consente assegnazioni a sinistra di ->. Quindi non c'è alcuna ambiguità tra questi operatori possibili e la regola di precedenza, sebbene esplicitamente dichiarata nel JLS, diventa insignificante.

Ciò consente di compilare, ad esempio un tale gioiello, senza ambiguità:

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

10

Innanzitutto, spieghiamo qui il problema pratico.

Supponendo che tu abbia una definizione simile

IntUnaryOperator op;

Quanto segue è sintatticamente accettato e funziona come previsto:

op = x -> x;

Cioè, abbiamo una funzione di identità intassegnata alla opvariabile. Ma se =avessimo una priorità più elevata, ci aspetteremmo che Java lo interpreti come

(op = x) -> x;

Che non è sintatticamente valido, quindi dovrebbe essere un errore di compilazione. Quindi, in pratica, l'assegnazione non ha una precedenza maggiore rispetto alla freccia.

Ma anche ciò che segue è OK (supponiamo che tsia una variabile di classe / istanza di tipo int):

op = x -> t = x;

Questo compila e la funzione, se applicata, assegna il valore dell'operando te lo restituisce.

Ciò significa che la freccia non ha una precedenza più alta rispetto all'assegnazione t = x. Altrimenti sarebbe stato interpretato come

op = ( x -> t ) = x

e chiaramente, questo non è ciò che accade.

Quindi sembra che le operazioni abbiano la stessa precedenza. Inoltre, sono associativi. Ciò è implicito nella grammatica del capitolo 19 di JLS :

Expression:
  LambdaExpression
  AssignmentExpression

LambdaExpression:
  LambdaParameters -> LambdaBody

...

LambdaBody:
  Expression
  Block

Quindi il lato destro del corpo lambda ci riporta a Expression, il che significa che possiamo avere un lambda (a priorità più alta) al suo interno, o un incarico (a priorità più alta) in esso. Ciò che intendo per "priorità più alta" è che più si approfondiscono le regole di produzione, prima verrà valutata l'espressione.

Lo stesso vale per l'operatore di assegnazione:

AssignmentExpression:
  ConditionalExpression
  Assignment

Assignment:
  LeftHandSide AssignmentOperator Expression

Ancora una volta, il lato destro del compito ci riporta a Expression, così possiamo avere un'espressione lambda o un compito lì.

Quindi, piuttosto che fare affidamento sul testo JLS, la grammatica ci fornisce una descrizione ben definita della situazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.