【问题标题】:Is it good solution to use checked decorator function in Stream API?在 Stream API 中使用检查的装饰器函数是一个好的解决方案吗?
【发布时间】:2016-08-06 03:24:11
【问题描述】:

我正在使用 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

【问题讨论】:

  • 你应该看看 JavaRx,它提供了一个很好的 API 用于错误处理的流媒体
  • 谢谢,我试了好几次,但总是放弃。也许这是我需要整理的信号。

标签: java function exception lambda java-stream


【解决方案1】:

如果抛出 IOException 以外的任何内容,您将获得 ClassCastException,因为您捕获了所有 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);
            }
        };
    }
}

【讨论】:

  • 不是真的, 从我使用的方法推断。因此,如果我将使用抛出 IOException 的方法,它将是 并且在 exceptionHandler 中,您将获得 IOException 类型的 e,如果它抛出任何其他 e 将是它的类型(或者如果有,则为 Throwable 类型)多个例外)。例如,您可以运行示例并查看输出 gist.github.com/gavlyukovskiy/30e28bae4b572b5a67c3a7c432069f46
  • 这是一个有趣的想法。是否有任何通常抛出的最终异常类型?
  • 通常我们只使用单个异常,因此可以使用未经检查的模拟来处理它。或者我们经常抛出 UserApiException 来表示用户请求问题。
  • @Monk3D: CE 可以推断为目标方法声明的已检查异常,实际上,目标方法不能抛出其他已检查异常。尽管如此,catch(Throwable) 也会捕获所有 unchecked 异常,即RuntimeExceptions 和Errors,所以这个答案是有道理的。正确的解决方案是在之前对它们进行排序:catch(RuntimeException|Error unchecked) { throw unchecked; } catch(Throwable checkedException) { throw exceptionHandler.apply(t, (CE)checkedException); } 但请注意,无法表达导致CE 必须是已检查异常的要求。
  • @Holger,谢谢,我更新了答案。最后一句我没完全理解,你能举个例子吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
  • 1970-01-01
  • 2020-04-27
  • 1970-01-01
  • 1970-01-01
  • 2021-08-29
相关资源
最近更新 更多