I have encountered that I must catch all checked exceptions inside stream expresions. I have read very popular topic:
How can I throw CHECKED exceptions from inside Java 8 streams?
And there is answer which suugest following approach:
we have 3 strings:
"java.lang.Object"
"java.lang.Integer"
"java.lang.Strin"
We want to load classes by name.
Thus we need to use Class#forName
method
Class#forName java doc)
As you can see following method declaration contains
throws ClassNotFoundException
Thus if we use usual loop we need to write followig code:
public void foo() throws ClassNotFoundException {
String arr[] = new String[]{"java.lang.Object", "java.lang.Integer", "java.lang.Strin"};
for(String className:arr){
Class.forName(className);
}
}
lets try to rewrite it using streams:
public void foo() throws ClassNotFoundException {
String arr[] = new String[]{"java.lang.Object", "java.lang.Integer", "java.lang.Strin"};
Stream.of(arr).forEach(Class::forName);
}
compiler says that:
Error:(46, 32) java: incompatible thrown types java.lang.ClassNotFoundException in method reference
Ok, lets try to use approach from topic mentioned above:
we create following methods:
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) {
return t -> {
try {
consumer.accept(t);
} catch (Exception exception) {
throwAsUnchecked(exception);
}
};
}
@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
void accept(T t) throws E;
}
@SuppressWarnings("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E {
throw (E) exception;
}
And client code will looks like this:
public void foo() throws ClassNotFoundException {
String arr[] = new String[]{"java.lang.Object", "java.lang.Integer", "java.lang.Strin"};
Stream.of(arr).forEach(rethrowConsumer(Class::forName));
}
I want to know how does it work. It is really unclear for me.
lets research rethrowConsumer:
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) {
return t -> {
try {
consumer.accept(t);
} catch (Exception exception) {
throwAsUnchecked(exception);
}
};
}
and throwAsUnchecked signature look slike
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E {
Please clarify this mess.
P.S.
I localized that magic happens inside throwAsUnchecked
because following snippet correct
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) {
return t -> {
try {
throw new Exception();
} catch (Exception exception) {
throwAsUnchecked(exception);
}
};
}
But following not
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) {
return t -> {
try {
consumer.accept(t);
} catch (Exception exception) {
throw new Exception();
//throwAsUnchecked(exception);
}
};
}