Когда фигурные скобки необязательны в синтаксисе лямбда Java 8?

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

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

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


person hertzsprung    schedule 21.06.2012    source источник
comment
если он все еще находится в разработке и может быть изменен, зачем вообще спрашивать? ответ мог сразу устареть.   -  person user12345613    schedule 21.06.2012
comment
Потому что я хотел бы понять причину этого.   -  person hertzsprung    schedule 21.06.2012
comment
откуда вы берете метод фильтрации? У меня есть версия лямбда java 8, и код yr не компилируется.   -  person NimChimpsky    schedule 04.11.2012
comment
@NimChimpsky: У вас есть лямбда b39? Лямбда-API все еще находятся в разработке, поэтому методы могут быть изменены.   -  person hertzsprung    schedule 04.11.2012
comment
@hertzsprung не уверен, вчера было ...? Хотя у меня лямбда работает правильно (ну, вроде правильно, stackoverflow.com/q/13219297/106261). Но код yr предполагает, что метод фильтра находится на итеративном интерфейсе, я не могу найти ссылку для этого   -  person NimChimpsky    schedule 04.11.2012
comment
@NimChimpsky: Вероятно, это связано с тем, что лямбда-методы теперь принадлежат интерфейсу Stream, а не Iterable, как раньше.   -  person hertzsprung    schedule 05.11.2012
comment
@hertzsprung есть ли какие-нибудь документы?   -  person NimChimpsky    schedule 05.11.2012
comment
@NimChimpsky: Я ничего не знаю, кроме исходного кода. Лучше всего выполнить поиск в списке рассылки lambda-dev и разместите там, если вам нужно.   -  person hertzsprung    schedule 05.11.2012
comment
Сейчас этот вопрос кажется спорным, так как в фактически выпущенной версии Java 8 оба примера в вопросе принимаются компилятором и работают правильно. Вторую лямбду можно даже заменить ссылкой на метод.   -  person LordOfThePigs    schedule 05.01.2015


Ответы (4)


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

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

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

person jpm    schedule 21.06.2012
comment
Я считаю, что это просто повторение того, что сказал OP, и добавление некоторых дополнительных деталей, без ответа на запрошенное почему, если я что-то не упускаю. - person Kevin Welker; 22.06.2012
comment
Думаю, это проясняет мне ситуацию. Утверждения не являются выражениями, потому что они не могут быть оценены. Скобки необязательны, если тело лямбда является выражением, но они обязательны, если тело является оператором или серией операторов. Звучит правильно, @jpm? - person hertzsprung; 22.06.2012
comment
Около. Следует пояснить, что выражения являются типом операторов (т.е. все выражения являются операторами, но не все операторы являются выражениями). Также обратите внимание, что блок (код, окруженный {}) синтаксически является одним оператором. Было бы более ясно сказать, что тело лямбды может содержать единственный оператор, который может быть либо выражением, либо блок-оператором. - person jpm; 22.06.2012
comment
Кажется, что это изменилось, в Lambda Tutorial теперь говорится: в лямбда-выражении операторы необходимо заключать в фигурные скобки ({}). Однако необязательно заключать вызов метода void в фигурные скобки. Например, следующее допустимое лямбда-выражение: email -> System.out.println(email) - person meyertee; 23.06.2013
comment
Кажется, что вызов метода с возвратом чего-то тоже может быть без фигурных скобок. public interface ReturnString { String get(String s); } public class Main { public static void main(String[] args) { ReturnString returnString = s -> new Object().toString(); System.out.println(returnString.get("")); } } - person Boreas320; 08.09.2015

Это просто: EG (в основном) приняла решение по синтаксису.

Рассмотрев ряд альтернатив, мы решили по существу принять синтаксис C #. Мы все еще можем обсудить более тонкие моменты (например, тонкая стрелка против толстой стрелки, специальная нулевая форма и т. Д.), Но еще не пришли к решению по синтаксису ссылок на методы.

Синтаксис C #:

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

person Ishtar    schedule 21.06.2012

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

person cuddlebugCuller    schedule 08.04.2013

Я пробовал ваш код и думаю, что для самой последней версии JRE все будет в порядке.

Ниже приводится ссылка на документы Oracle Java.

В лямбда-выражении операторы необходимо заключать в фигурные скобки ({}). Однако необязательно заключать вызов метода void в фигурные скобки.
Например, следующее допустимое лямбда-выражение:

email -> System.out.println(email)

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

Ссылки: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

person Euclid Ye    schedule 05.11.2015