Handle checked exceptions in Java8 streams

user10367961 :

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!

Alex Shesterov :

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.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=79493&siteId=1