Вопрос по lambda, java, java-8 – Когда скобки необязательны в лямбда-синтаксисе Java 8?

18

Я понимаю, что лямбда-реализация Java 8 подвержена изменениям, но в лямбда-сборке b39 я обнаружил, что фигурные скобки могут быть опущены только тогда, когда лямбда-выражение возвращает тип, отличный от void. Например, это компилирует:

public class Collections8 {
        public static void main(String[] args) {
                Iterable<String> names = Arrays.asList("Alice", "Bob", "Charlie");
                names.filter(e -> e.length() > 4).forEach(e -> { System.out.println(e); });
        }
}

Но удаление скобок так:

names.filter(e -> e.length() > 4).forEach(e -> System.out.println(e));

выдает ошибку

Collections8.java:6: error: method forEach in interface Iterable<T> cannot be applied to given types;
        names.filter(e -> e.length() > 4).forEach(e -> System.out.println(e));
                                         ^
  required: Block<? super String>
  found: lambda
  reason: incompatible return type void in lambda expression
  where T is a type-variable:
    T extends Object declared in interface Iterable

Кто-нибудь может объяснить, что здесь происходит?

@NimChimpsky: У вас есть лямбда-B39? Лямбда-API все еще в движении, поэтому методы могут быть изменены. hertzsprung
если он все еще находится в стадии разработки и может быть изменен, зачем вообще спрашивать? ответ может быть устаревшим сразу. user12345613
Потому что я хотел бы понять причины этого. hertzsprung
Этот вопрос сейчас кажется спорным, так как в фактически выпущенной версии Java 8 оба примера в этом вопросе приняты компилятором и работают правильно. Вторая лямбда может быть даже заменена ссылкой на метод. LordOfThePigs
откуда вы получаете метод фильтра? У меня Java 8 лямбда-версия, и ваш код не компилируется. NimChimpsky

Ваш Ответ

4   ответа
1

я думаю, это будет хорошо.

Далее я ссылаюсь на Oracle Java-документы.

In a lambda expression, you must enclose statements in braces ({}). However, you do not have to enclose a void method invocation in braces.
For example, the following is a valid lambda expression:

email -> System.out.println(email)

И документ объясняет довольно четко. Надеюсь, что это может решить вашу проблему.

Рекомендации:https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

10

After considering a number of alternatives, we decided to essentially adopt the C# syntax. We may still deliberate further on the fine points (e.g., thin arrow vs fat arrow, special nilary form, etc), and have not yet come to a decision on method reference syntax.

The C# syntax is:

lambda = ArgList Arrow Body
ArgList = Identifier
           | "(" Identifier [ "," Identifier ]* ")"
           | "(" Type Identifier [ "," Type Identifier ]* ")"
Body = Expression
           | "{" [ Statement ";" ]+ "}"

Выражение оценивает что-то, у вас не может быть пустых выражений в Java. Это утверждение, поэтому вам нужно{} вокруг него.

http://mail.openjdk.java.net/pipermail/lambda-dev/2011-September/003936.html

0

лямбда-выражение автоматически возвращает одно выражение после - & gt; оператор.
Таким образом, когда у вас есть лямбда, которая ничего не возвращает, вы должны использовать фигурные скобки

19

когда лямбда-тело представляет собой одиночное выражение или вызов метода void. Каждое выражение оценивается как значение и поэтому не может быть недействительным.

Если тело лямбда является блоком утверждений (например, серия вычислений, сопровождаемаяreturn утверждение), или лямбда не имеет значения (то есть имеетvoid тип возврата) и не является единственным вызовом метода void, вы должны использовать блочную форму, которая требует скобок.

В лямбде в стиле блока, если значениеreturned, тогда все возможные пути кода должны либоreturn значение илиthrow Throwable.

@meyertee Спасибо за исправление.
Я полагаю, что это просто повторяет сказанное ФП и добавляет некоторые дополнительные подробности, не отвечая на запрошенный вопрос «почему», если я что-то не упустил.
Это, кажется, изменилось,Lambda Tutorial теперь говорится: «В лямбда-выражении вы должны заключать операторы в фигурные скобки ({}). Однако вам не нужно заключать вызов метода void в фигурные скобки. Например, следующее является допустимым лямбда-выражением:email -> System.out.println(email)& Quot;
Я думаю, что это проясняет вещи для меня. Заявления не являются выражениями, потому что они не могут быть оценены. Скобки необязательны, если лямбда-тело является выражением, но они обязательны, если тело является выражением или серией выражений. Звучит правильно, @jpm? hertzsprung
Почти. Следует уточнить, что выражения являются типом утверждения (то есть все выражения являются утверждениями, но не все выражения являются выражениями). Также обратите внимание, что блок (код, окруженный{}), синтаксически, одно утверждение. Может быть более ясно сказать, что тело лямбды может содержать один оператор, который может быть либо выражением, либо оператором блока.

Похожие вопросы