-1

Let's taken some simple example code:

Employee employee = repository.findById(id).orElseThrow(() -> new EmployeeNotFoundException(id));

From my understanding, the lambda is used to create a subistute of a functional interface (only 1 method), and empty parenthesis means that the method has no parameters.

But what method is called in orElseThrow that a lambda is needed? I thought it is either an Optional or an Exception.

So my question is: How would this look like without a lambda call?

Employee class:

class Employee {

    private Long id;
    private String name;
    private String role;

    Employee() {}

    Employee(String name, String role) {
        this.name = name;
        this.role = role;
    }
}

and the exception class:

class EmployeeNotFoundException extends RuntimeException {

    EmployeeNotFoundException(Long id) {
        super("Could not find employee " + id);
    }
}

EDIT: I am interested in how to write a valid, compilable substitution for the lambda- expression. Right now I am at

        Employee employee = repository.findById(id).orElseThrow(
            new Supplier<Throwable>() {
                @Override
                public Throwable get() {
                    return new EmployeeNotFoundException(id);
                }
            }
        )

but that is not right, since now I would need to add the exception to the method signature, which is not the case when using the lambda..it shows that I don't know how to implement the supplier class by hand instead of just skipping all that by the use of lambdas

Leviathan
  • 644
  • 1
  • 15
  • 30
  • What search and research have you done prior to asking? Looked at [the documentation](https://docs.oracle.com/javase/10/docs/api/java/util/Optional.html#orElseThrow(java.util.function.Supplier)), for example? Please when asking search and research first, and tell us what you found and how it was insufficient. It makes for better questions — and for better answers, so it’s for your own sake. – Ole V.V. Oct 02 '19 at 13:11
  • 1
    Related: [Java 8 method references: provide a Supplier capable of supplying a parameterized result](https://stackoverflow.com/questions/22917138/java-8-method-references-provide-a-supplier-capable-of-supplying-a-parameterize). – Ole V.V. Oct 02 '19 at 13:12
  • I have read the documentation, but my java knowledge is a bit rusty and I am having a hard time understanding what exactly is substituted. I don't know how to write orElseThrow without the lambda, e.g. putting in the supplier as anonoymous class there – Leviathan Oct 02 '19 at 13:27

4 Answers4

2

This is answered very easily by looking at the JavaDoc for Optional:

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

The lambda parameter is a supplier which supplies an exception to be thrown.

Ben R.
  • 1,965
  • 1
  • 13
  • 23
2

orElseThrow is a method of the Optional class having the following signature:

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X

This means the lambda expression you are passing must conform to the Supplier<? extends X> functional interface. The Supplier<T> functional interface has a single method that accepts no arguments and returns an instance of T: T get().

Your lambda expression - () -> new EmployeeNotFoundException(id) - matches this functional interface.

This functional interface's get() method is used to create the Throwable instance that orElseThrow() would throw when the Optional is empty.

Eran
  • 387,369
  • 54
  • 702
  • 768
1

Optional::orElseThrow takes a Supplier and this Supplier is used to get an instance of Exception which will be thrown if Optional has null value underneath. See the implementation for Optional::orElseThrow :

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (this.value != null) {
        return this.value;
    } else {
        throw (Throwable)exceptionSupplier.get();
    }
}

it simply checks if value is there and if not - it gets the Execption instance from Supplier and throws it.

And the expression :

() -> new EmployeeNotFoundException(id)

is conformant to Supplier expected by Optional::orElseThrow method - Supplier<? extends X> exceptionSupplier where X extends Throwable. It could be even extracted to separate variable :

Supplier<EmployeeNotFoundException> execptionSupplier = () -> new EmployeeNotFoundException(id);
Employee employee = repository.findById(id).orElseThrow(execptionSupplier);
Michał Krzywański
  • 15,659
  • 4
  • 36
  • 63
1

I haven’t tested, but I believe that to avoid having to handle a general Throwable (by declaring it in your method signature or catching it within your enclosing method) you need to provide a Supplier<RuntimeException> or similar with an even more specific type than RuntimeException. For example:

    Employee employee = repository.findById(id).orElseThrow(
        new Supplier<EmployeeNotFoundException>() {
            @Override
            public EmployeeNotFoundException get() {
                return new EmployeeNotFoundException(id);
            }
        }
    );

Since EmployeeNotFoundException is a RuntimeException and thus an unchecked exception, with the above the compiler won’t care whether you handle the exception.

You have read the documentation correctly, at least partially: What we are passing to orElseThrow is a Supplier, so this is the interface that the lambda implements and the interface we need to implement no matter if we pass a method reference, a lambda or as in your case, an object instantiated with new. Supplier is a generic interface taking one type argument. The documentation also tells us that orElseThrow expects a Supplier<? extends X> where X extends Throwable, that is, X is a subtype of Throwable. So passing a Supplier<Throwable> is not incorrect, but as you experienced, it gave you some trouble elsewhere. And we are allowed to put in any subtype of Throwable instead. Putting in either RuntimeException or EmployeeNotFoundException frees us from the trouble.

I don’t know why you should want to be so wordy, though, when the lambda is working fine.

Link: Documentation of the Supplier interface

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161