isPresent
method unless you are using an old school if statement. The second problem is of course the old chestnut that even if you could do that the methods would not be able to throw a checked exception. (Yes you can wrap with a RuntimeException but it is not the prettiest.)The workaround I found was to use the map function as the success case and the orElseGet to return the failure case. In both branches the code returns an instance of ThrowingRunnable by having a lambda return a lambda. The
run()
is then called at the end and it can throw any exception it wants to.@FunctionalInterface public interface ThrowingRunnable<E extends Throwable> { public void run() throws E; } Optional<Credential> credential = .... credential.<ThrowingRunnable<IOException>>map(auth -> () -> { PasswordWrapper pw = auth.getToken(); ... // something that might throw an IOException }).orElseGet(() -> () -> { response.setStatus(401); LOGGER.log(Level.INFO, "credential is not found"); } ).run();
This is possibly excessive for this particular use case; but I can see this technique being useful elsewhere and it is worth knowing what it looks like so it is not a surprise in others code.
Update 14th March 2016: Thanks to Michael Rasmussen on the DZone version of this article he noted I could use
orElse
rather than orElseGet
to remove the second double lambda.credential.<ThrowingRunnable<IOException>>map(auth -> () -> { PasswordWrapper pw = auth.getToken(); ... // something that might throw an IOException }).orElse(() -> { response.setStatus(401); LOGGER.log(Level.INFO, "credential is not found"); } ).run();