Подтвердить что ты не робот

Зачем нужно заключать заявления с полным блоком кода в лямбда-теле?

Если в лямбда-функции есть один оператор, мы можем опустить определение полного кода для него:

new Thread(() -> System.out.println());

Почему это не так для операторов, которые генерируют исключения? Это дает ошибку компиляции с указанием '{' expected:

new Thread(() -> throw new RuntimeException());

Конечно, включение лямбда-тела в кодовый блок работает:

new Thread(() -> {
    throw new RuntimeException();
});
4b9b3361

Ответ 1

Оператор

A throw - это утверждение, а не выражение, поэтому оно должно быть помещено в фигурные скобки. Согласно в этой статье, группа экспертов Java провела неофициальное исследование синтаксиса лямбда в то время, и было четыре варианта:

  • Strawman: #(arglist)(expr) and #(arglist){statements}
  • BGGA: { args -> statements } (аналогично Scala и Groovy)
  • SotL: #{ args -> statements}
  • Редмонд: (args) -> { statements }

В конечном счете, выбор заключался в том, чтобы использовать синтаксис, аналогичный синтаксису С# в соответствии с этот поток, который также близок к последнему варианту выше насколько я вижу. В С# существует различие между выражением lambdas и statement lambdas:

Выражение lambda (С#):

(input parameters) => expression

Заявление lambda (С#):

(input parameters) => {statement;}  

Синтаксис объясняется в этой странице документации MSDN.

И обоснование выбора этого синтаксиса над другими параметрами упоминается в предыдущем потоке:

Решение о выборе этого синтаксиса было двояким:

  • Синтаксис оценивается "очень хорошо" по большинству субъективных мер (хотя имеет случаи, когда это выглядит плохо, как и все остальные). В в частности, он хорошо справляется с "малыми" лямбдами, которые используются как метод аргументы (общий случай), а также хорошо с большими (многозадачность) лямбда.

  • Несмотря на обширный поиск, среди победителей альтернативы (каждая форма имела некоторые хорошие аспекты, а некоторые действительно не очень хорошие аспекты, и не было формы, которая была бы явно лучше, чем другие). Итак, мы чувствовали, что лучше выбрать то, что имеет как было показано, хорошо работает на двух языках, которые больше всего напоминают Java - С# и Scala - вместо того, чтобы придумывать что-то новое.

Ответ 2

AFAIK jls говорит, что тело лямбда должно быть:

или блок. Имея это так:

new Thread(() -> throw new RuntimeException());

нет, и компилятор каким-то образом информирует вас об этом.

Объявление следующего вида:

 new Thread(() -> {
     throw new RuntimeException();
 });

делает его блоком. Вот соответствующая часть:

Блок представляет собой последовательность операторов, деклараций локальных классов и объявлений локальных переменных в фигурных скобках.

Ответ 3

В Java8 грамматика лямбда-тела принимает только выражение или block. В то время как throwing exception является оператором , а не выражением .

throwStatement: 'throw' expression ';' ;

lambdaBody: expression | block;

expression: lambdaExpression | assignmentExpression;

block : '{' blockStatements? '}' ;

Возможно, его можно улучшить, включив throwStatement в lambdaBody в следующей версии jdk, если это необходимо. В самом деле, нам это нужно, как вы упомянули выше. например:

lambdaBody: expression | block | throwStatement;