Lets say you have a 3rd party library which exposes the next interface.
interface Mapper {
String doMap(String input) throws CheckedException;
}
class CheckedException extends Exception {
}
I am aware checked exception are generally a bad practice in Java, but this code comes from a 3rd party and I can't modify it.
I want to use an implementation of the Mapper interface in combination with the Java8 streams API. Consider the sample implementation below.
class MapperImpl implements Mapper {
public String doMap(String input) throws CheckedException {
return input;
}
}
Now, I would like to apply the mapper to a collection of strings, for example.
public static void main(String[] args) {
List<String> strings = Arrays.asList("foo", "bar", "baz");
Mapper mapper = new MapperImpl();
List<String> mappedStrings = strings
.stream()
.map(mapper::doMap)
.collect(Collectors.toList());
}
The code fails to compile, since Function does not know how to handle the CheckedException declared by doMap. I came up with two possible solutions.
Solution #1 - wrap invocation
.map(value -> {
try {
return mapper.doMap(value);
} catch (CheckedException e) {
throw new UncheckedException();
}
})
Solution #2 - write an utility method
public static final String uncheck (Mapper mapper, String input){
try {
return mapper.doMap(input);
} catch (CheckedException e){
throw new UncheckedException();
}
}
And then I can use
.map(value -> Utils.uncheck(mapper, value))
Which is, in your opinion, the best approach to deal with checked exceptions in the context of Java8 streams (and in the broader context of lambda expressions)?
Thanks!
You've basically listed two viable options.
One more option is to make the checked exceptions be thrown out of the stream processing function ("propagate" or "sneak" a checked exception). This is done by catching a checked exception and re-throwing it as a RuntimeException
(by casting). Take a look at this great answer for details.
Multiple libraries have been developed to deal with exception handling in stream API. For example, you may take a look at the NoException library: https://noexception.machinezoo.com/
It gives you a convenient way to wrap / sneak / log / ignore checked or unchecked exceptions.
For example, in your case it would be:
.map(value -> Exceptions.sneak().function(mapper::doMap))
or
.map(value -> Exceptions.wrap().function(mapper::doMap))
P.S.: I'm NOT the author of the library, nor a contributor, but I've used this library in several projects.