Handle checked exceptions in Java8 streams [duplicate]
Handle checked exceptions in Java8 streams [duplicate]
This question already has an answer here:
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!
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
java.util.function
Utils.uncheck
Does your mapper actually ever throw anything? Or is the mapper itself from the lib as well? Right now you could just remove the
throws CheckedException
from the implementing class and no longer reference the interface but the mapper class itself.– luk2302
Sep 17 '18 at 11:49
throws CheckedException
@luk2302 Yes, the mapper implementation is part of the lib as well.
– user10367961
Sep 17 '18 at 11:56
2 Answers
2
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.
RuntimeException
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.
Looks like a clean way to do it, thanks!
– user10367961
Sep 17 '18 at 12:53
You can look at the library faux-pas that simplifies error handling for Functional Programming in Java. I think it's great to manage check exception in stream.
P.S.: I'm NOT the author of the library, nor a contributor, but I've used this library in several projects.
Will look into it, thanks!
– user10367961
Sep 17 '18 at 12:53
Both solutions are essentially the same thing. The lambda (Solution 1) creates an instance of
java.util.function
that does the try/catching, Solution 2 delegates that work to the named functionUtils.uncheck
. Since you are forced to catch the Exception, there's no useful way around this.– f1sh
Sep 17 '18 at 11:46