Java 泛型异常包装器的应用

Java 泛型异常包装器的应用,存在一个抛出异常的 lambda 表达式,但用户希望使用泛型包装器(generic wrapper)来捕获所有受检异常,并将它们作为非受检异常重新抛出。创建特殊的异常类(exception class),添加一个接受这些类的泛型方法,并返回不抛出异常的 lambda 表达式。

Java 泛型异常包装器的应用 问题描述

存在一个抛出异常的 lambda 表达式,但用户希望使用泛型包装器(generic wrapper)来捕获所有受检异常,并将它们作为非受检异常重新抛出。

Java 泛型异常包装器的应用 解决方案

创建特殊的异常类(exception class),添加一个接受这些类的泛型方法,并返回不抛出异常的 lambda 表达式。

Java 泛型异常包装器的应用 具体实例

范例利用提取的方法实现异常处理和范例受检异常与lambda表达式讨论了如何委托一个单独的方法来处理 lambda 表达式抛出的异常,不过我们需要为每个可能抛出异常的操作定义一个私有方法。可以采用泛型包装器使其更为通用。
为此,我们定义一个单独的函数式接口,它包含一个声明抛出 Exception 的方法,然后通过某种包装器方法(wrapper method)将其连接到用户代码。
例如,Stream 接口的 map 方法需要一个 Function,但 Function 接口的 apply 方法不会声明任何受检异常。为了在 map 方法中使用可能抛出受检异常的 lambda 表达式,我们创建一个单独的函数式接口,声明它将抛出 Exception,如例 5-39 所示。

例 5-39 抛出 Exception 的函数式接口

@FunctionalInterface
public interface FunctionWithException<T, R, E extends Exception> {
    R apply(T t) throws E;
}

接下来,在 try/catch 代码块中包装 apply 方法,以添加一个传入 FunctionWithException 并返回 Function 的包装器方法,如例 5-40 所示。

例 5-40 用于处理异常的包装器方法

private static <T, R, E extends Exception>
    Function<T, R> wrapper(FunctionWithException<T, R, E> fe) {
        return arg -> {
            try {
                return fe.apply(arg);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        };
}

如上所示,wrapper 方法接受抛出 Exception 的代码,并构建必要的 try/catch 块,同时委托给 apply 方法。在本例中,wrapper 方法被声明为 static,但这并非强制要求。如例 5-41 所示,我们可以使用任何抛出异常的 Function 来调用包装器。

例 5-41 泛型静态包装器方法的应用

public List<String> encodeValuesWithWrapper(String... values) {
    return Arrays.stream(values)
        .map(wrapper(s -> URLEncoder.encode(s, "UTF-8"))) ➊
        .collect(Collectors.toList());
}

➊ 使用 wrapper 方法
接下来,可以在抛出异常的 map 操作中编写代码,wrapper 方法会将其作为未受检异常重新抛出。这种方案的不足之处在于,需要为所有计划使用的函数式接口创建单独的泛型包装器(如 ConsumerWithExceptionSupplierWithException)。
这未免有些复杂。有鉴于此,不难理解为何某些 Java 框架(如 Spring 和 Hibernate)甚至整个语言(如 Groovy 和 Kotlin)在捕获所有受检异常后,再将它们作为非受检异常重新抛出。

赞(1)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Java 实例