Checked Exceptions
One thing that might catch you off guard is how lambdas and method references interact with checked exceptions.
Normally if the implementation of a functional interface throws an exception that is allowed.
class Main {
void main() {
Function<String, Integer> parseObject
= Integer::parseInt;
int x = parseObject.apply("1657");
IO.println(x);
}
}
But if the implementation throws a checked exception Java will complain.
This is because checked exceptions need to be declared in a method signature. If the functional interface you are making an implementation does not declare a checked exception is thrown in its single method
import module java.base;
@FunctionalInterface
interface Loader<T> {
T load();
}
class Main {
void main() throws IOException {
Files.writeString(Path.of("one.txt"), "One and only one");
// Files.readString can throw an IOException and that is checked
Loader<String> loader = () -> Files.readString(Path.of("one.txt"));
IO.println(loader.load());
}
}
One solution is to edit the functional interface such that it declares the thrown exception.
import module java.base;
@FunctionalInterface
interface Loader<T> {
// If we add this throws it will be fine.
T load() throws IOException;
}
class Main {
void main() throws IOException {
Files.writeString(Path.of("one.txt"), "One and only one");
Loader<String> loader = () -> Files.readString(Path.of("one.txt"));
IO.println(loader.load());
}
}
The other solution is to catch and rethrow any exceptions as unchecked.
import module java.base;
@FunctionalInterface
interface Loader<T> {
T load();
}
class Main {
void main() throws IOException {
Files.writeString(Path.of("one.txt"), "One and only one");
Loader<String> loader = () -> {
try {
return Files.readString(Path.of("one.txt"));
} catch (IOException e) {
// No issue throwing unchecked exceptions
throw new UncheckedIOException(e);
}
};
IO.println(loader.load());
}
}
Which of those two solutions you pick will be context dependent.
If you don't control the implementation of the functional interface
(such as with the built-in Runnable
, Function
, Supplier
, etc.)
your best option is the second one.