Here's a silly example, replete with dubious practices for the sake of conciseness :)
Food makeLunch() {
try {
return kitchen.makeSandwich();
}
catch (KitchenClosedException ex) {
handleException(ex, "Couldn't make a sandwich :(");
}
catch (NoBreadException ex) {
handleException(ex, "Couldn't make a sandwich :(");
}
return null;
}
void handleException(Exception ex, String message) throws RuntimeException {
log.error("Something went wrong", ex);
throw new RuntimeException(message, ex);
}
Kasper points out that the 'return null;' statement at the end of the makeLunch() method is pointless - although we can see that it will never be executed, the compiler requires it because the signature of the handleException() method only says that it may throw an exception, but does not guarantee it.
There's some discussion of the 'problem' here, including alternative ways to structure the code.
With the BGGA closures prototype though, we can rewrite the example as follows:
Sandwich makeLunch() {
try {
return kitchen.makeSandwich();
}
catch (KitchenClosedException | NoBreadException ex) {
handleException(ex, "Couldn't make a sandwich :(");
}
}
Nothing handleException(Exception ex, String message) throws RuntimeException {
log.error("Something went wrong", ex);
throw new RuntimeException(message, ex);
}
There are three changes to the original example here:
- BGGA allows us to catch multiple types of exception with one catch clause.
- The signature of the handleException() method now has a return type of java.lang.Nothing, which guarantees that the method will not 'complete normally' (because it always throws an exception). The compiler can enforce this guarantee, and we can take advantage of it:
- Because of the above change, the 'return null;' is neither required, nor allowed, since the compiler now knows that the statement can never be executed.
Which is nice.