19

I realise that the Java 8 lambda implementation is subject to change, but in lambda build b39, I've found that braces can only be omitted when the lambda expression returns a non-void type. For example, this compiles:

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); });
        }
}

But removing the braces like this:

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

gives the error

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

Can anyone explain what's going on here?

hertzsprung
  • 9,445
  • 4
  • 42
  • 77
  • 1
    if it's still under development and subject to change why even ask? the answer could be outdated immediately. – user12345613 Jun 21 '12 at 19:54
  • 11
    Because I'd like to understand the reasoning behind it. – hertzsprung Jun 21 '12 at 19:56
  • 1
    where do you get the filter method from ? I have java 8 lambda versin, and yr code does not compile. – NimChimpsky Nov 04 '12 at 17:52
  • @NimChimpsky: Do you have lambda b39? The lambda APIs are still in flux so methods are subject to change. – hertzsprung Nov 04 '12 at 18:55
  • @hertzsprung not sure, dl'd yesterday ... ? Although I do have lambda's working correctly (well kinda correctly http://stackoverflow.com/q/13219297/106261). But yr code suggests filter method is on iterable interface, I can't find any reference for that – NimChimpsky Nov 04 '12 at 19:32
  • @NimChimpsky: This is likely because lambda methods now belong to a `Stream` interface rather than `Iterable` as before. – hertzsprung Nov 04 '12 at 21:55
  • @hertzsprung are there any docs available ? – NimChimpsky Nov 05 '12 at 07:30
  • @NimChimpsky: Beyond the source code, I'm not aware of any. Your best bet is to search the [lambda-dev](http://mail.openjdk.java.net/mailman/listinfo/lambda-dev) mailing list, and post there if you need to. – hertzsprung Nov 05 '12 at 07:59
  • 3
    This question seems moot now, as in the actual released version of Java 8, both of the examples in the question are accepted by the compiler and work correctly. The second lambda can even be replaced by a method reference. – LordOfThePigs Jan 05 '15 at 17:44

4 Answers4

23

You may omit the braces when the lambda body is a single expression or a void method invocation. Every expression evaluates to a value, and thus cannot be void.

If the body of the lambda is a block of statements (e.g. a series of calculations followed by a return statement), or the lambda has no value (i.e. has a void return type) and is not a single void method invocation, you must use the block form, which requires brackets.

In a block-style lambda, if a value is returned, then all possible code paths must either return a value or throw a Throwable.

jpm
  • 3,165
  • 17
  • 24
  • 1
    I believe this is just repeating what the OP said and adds some additional details, without answering the requested "why", unless I'm missing something. – Kevin Welker Jun 21 '12 at 20:16
  • I think this clarifies things for me. Statements are not expressions because they cannot be evaluated. Braces are optional if the lambda body is an expression, but they are mandatory if the body is a statement, or series of statements. Does that sound right, @jpm? – hertzsprung Jun 21 '12 at 20:35
  • 2
    Nearly. It should be clarified that expressions are a type of statement (i.e. all expressions are statements, but not all statements are expressions). Also note that a block (code surrounded by `{}`) is, syntactically, a single statement. It may be more clear to say that the body of a lambda may contain a single statement, which can either be an expression or a block-statement. – jpm Jun 21 '12 at 20:43
  • This seems to have changed, the [Lambda Tutorial](http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html) now states: "in a lambda expression, you must enclose statements in curly braces ({}). However, you do not have to enclose a void method invocation in curly braces. For example, the following is a valid lambda expression: `email -> System.out.println(email)`" – meyertee Jun 23 '13 at 15:55
  • It seems that a method invocation with return something also can be without braces. `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("")); } }` – Boreas320 Sep 08 '15 at 15:53
11

This just in: the EG has (mostly) made a decision on syntax.

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 ";" ]+ "}"

An expression evaluates to something, you can't have void expressions in Java. It is a statement, thus you need {} around it.

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

Community
  • 1
  • 1
Ishtar
  • 11,542
  • 1
  • 25
  • 31
2

If there are no braces, the lambda automatically returns the one expression after the -> operator.
Thus, when you have a lambda that returns nothing, you must use the braces

2

I have tried your code and for the most up-to-date JRE version I think it would be ok.

The following is what I reference from Oracle Java docs.

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)

And the doc explains quite clearly. Hope this can solve your problem.

References: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

Nayuki
  • 17,911
  • 6
  • 53
  • 80
Euclid Ye
  • 501
  • 5
  • 13