Search code examples
javalambdaoption-type

Why Consumer or Supplier argument needs {} for multiple annotations


Let's say there's an Optional optString. Now if I use it as below:

optString.ifPresent({
    //some statements
    }, () -> throw new Exception());`, it fails to compile.

Why do I've to wrap the throw new Exception() inside curly braces {}.

Why can't I simply do () -> throw new Exception.

Why is the compiler treating throw and new as some states that should be in a block?

In IntelliJ it fails with compilation errors: expected ) expected { expected; and Unexpected token

A complete example:

class OptionalTest {

    Optional<String> testString() {
        return Optional.empty();
    }
    
    void getString() {
        var optStr = testString();
        optStr.ifPresentOrElse(s -> {
            
        }, () -> throw new RuntimeException());
    }
}

Solution

  • You cannot simply throw in the lambda expression the way you did since a lambda body is either a single expression or a block. The throw is a statement.

    You have to wrap throwing an exception into the block:

    optStr.ifPresentOrElse(
        str -> /*do something*/,
        () -> { throw new RuntimeException(); });
    

    It is also worth mentioning Optional#orElseThrow which is designed to actually throw an exception. The only argument passed into the Supplier is the way to instantiate the exception, the method just takes it and throws instead of you if the Optional is empty.

    optStr.orElseThrow(() -> new RuntimeException());