Java generics just aren't powerful enough to express that a higher order function's exceptions depend on its args, so pretty much everyone has given up on specific checked exceptions.
@FunctionalInterface
public interface ThrowingConsumer<T, E extends Throwable> {
void accept(T value) throws E;
}
public static <T, E extends Throwable> void forEach(Collection<T> elements, ThrowingConsumer<T, E> consumer) throws E {
for (T element : elements) {
consumer.accept(element);
}
}
There is a significant shortcoming, which is that you can't catch exceptions using the type parameter - this does not compile: public static <T, E extends Throwable> Optional<E> forEach(Collection<T> elements, ThrowingConsumer<T, E> consumer) {
for (T element : elements) {
try {
consumer.accept(element);
} catch (E e) { // <-- not allowed!
return Optional.of(e);
}
}
return Optional.empty();
}
You can kludge your way around that in various ways, but none of them are pretty.