组合两个具有不同异常类型的函数(java 泛型)

Composing two functions with different exception types (java generics)

假设我想实现一个 java.util.function.Function<T,R> 版本,它可以抛出一些异常类型 E。我所做的是创建一个名为 ThrowingFunction 的功能接口,如下所示:

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

现在就像在 java.util.function.Function<T,R> 中一样,我需要实现默认方法 compose,我需要的是组合两个不同的 ThrowingFunction 实例 并且很可能,他们可以有不同的抛出异常类型。所以这是我的尝试:

default <V, E1 extends Exception, E2 super E1 & E> ThrowingFunction<V, R, E2> compose(ThrowingFunction<? super V, ? extends T, ? extends E1> before)
{
    return v -> apply(before.apply(v));
}

当然,我得到一个编译器错误:

Syntax error on token "super", extends expected

正是在泛型参数的声明中 E2 super E1 & E.

那么,这个问题的可能解决方案是什么,我是否只是组合两个具有相同异常类型 E 的不同 ThrowingFunction 实例( 而这不是最好想要) ?

这里不能使用default方法;它必须是接口上的 static 方法。当您尝试使用 default 方法时,类型 E 已经被捕获,并且 Java 编译器将不允许您将类型 E2 声明为超类型正如您的编译器错误指示的那样,少了 2 种类型 EE1

当更改为 static 方法时,您可以根据需要自由声明异常类型参数。您可以声明超类型异常类型 S,然后是子类型异常类型 E1E2。然后其余的遵循类似于 Function 的默认 compose 方法。

此处的类型参数与 Function.compose 使用的相匹配,并添加了与异常相关的类型参数。

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

    /**
     * Composes f (after) and g (before) to produce the composed
     * function f o g(v), which executes f(g(v)).
     * @param f The function that will take g's output <T> as input to return the overall result <R>.
     * @param g The function that will take the overall input <V> and return f's input <T>.
     * @param <V> The input result type of the entire composed function (and of function g).
     * @param <T> The result type of g, used as input to f.
     * @param <R> The end result type of the entire composed function (and of function f).
     * @param <S> If any of f or g throws an exception, it is captured by the supertype exception class S.
     * @param <E1> The exception type thrown by f.
     * @param <E2> The exception type thrown by g.
     * @return A ThrowingFunction that whose input <V> is applied to g, whose result is passed to
     *     f to generate the overall result <R>.
     */
    static <V, T, R, S extends Exception, E1 extends S, E2 extends S> ThrowingFunction<V, R, S>
        compose(ThrowingFunction<? super T, ? extends R, ? extends E1> f,
                ThrowingFunction<? super V, ? extends T, ? extends E2> g)
    {
        return v -> f.apply(g.apply(v));
    }
}