在Stream API中使用已检查的装饰器功能是否很好?

时间:2016-04-14 13:57:42

标签: java function exception lambda java-stream

我正在使用Java 8 Stream API,因为我们知道它不支持java.util.function中任何功能接口内的已检查异常。

我通常必须在流操作中使用带有已检查异常的方法,并且我已经编写了CheckedFunction装饰器以在这些操作中使用:

import java.util.function.BiFunction;
import java.util.function.Function;

public interface CheckedFunction<T, R, E extends Throwable> {

    R apply(T t) throws E;

    static <T, R, CE extends Throwable, UCE extends RuntimeException> Function<T, R> checked(
            CheckedFunction<T, R, CE> checked, Function<CE, UCE> exceptionHandler) {
        return (t) -> {
            try {
                return checked.apply(t);
            }
            catch (RuntimeException | Error e) {
                throw e;
            }
            catch (Throwable e) {
                // can't catch - compiler error
                if (e instanceof InterruptedException) {
                    Thread.currentThread().interrupt();
                }
                throw exceptionHandler.apply((CE) e);
            }
        };
    }
}

所以我可以在这种情况下使用它:

entities.stream()
        .map(checked((entity) -> someResultChecked(entity), // throws IOException
                     (entity, e) -> { // e is of type IOException
                         log.error("exception during checked method of " + entity, e);
                         return new UncheckedIOException(e);
                     }))
        .map(checked((entity) -> saveToDb(entity), // throws SQLException
                     (entity, e) -> { // e is of type SQLException
                         log.error("exception during saving " + entity, e);
                         return new UncheckedSQLException(e);
                     }))
        .map(checked((entity) -> manyExceptionMethod(entity), // throws IOException, SQLException
                     (entity, e) -> { // e is of type Throwable
                         return new RuntimeException(e);
                     }))

它会将任何已检查的异常包装为未选中,但我知道如果方法抛出多个异常,它将擦除为Throwable,我将在简单的情况下使用它。

这是好主意,还是我可能遇到隐藏的障碍?

更新:重新运行RuntimeExceptions。

此外,我在jOOL中找到了更清晰的解决方案,处理InterruptedException,如果忽略它会导致不一致的行为: https://github.com/jOOQ/jOOL/blob/master/src/main/java/org/jooq/lambda/Unchecked.java

1 个答案:

答案 0 :(得分:0)

如果ClassCastException以外的其他内容被抛出,您将获得IOException,因为您正在捕获所有Throwable并将其传递到UncheckedIOException构造函数中,只需要IOException作为参数。由于在函数类型中捕获IOException是一种常见的需求,而不是试图概括,因此最好保持简单并为该检查的异常创建一个。我想你很少需要复制代码来为其他已检查的异常做同样的事情。

@FunctionalInterface
public interface CheckedIOFunction<T,R> {

    R apply(T t) throws IOException;

    static <T, R> Function<T, R> toUnchecked(CheckedIOFunction<T, R> function) {
        return t -> {
            try {
                return function.apply(t);
            } catch (IOException ioe) {
                throw new UncheckedIOException(ioe);
            }
        };
    }
}