组合两个具有不同异常类型的函数(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 种类型 E
和 E1
。
当更改为 static
方法时,您可以根据需要自由声明异常类型参数。您可以声明超类型异常类型 S
,然后是子类型异常类型 E1
和 E2
。然后其余的遵循类似于 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));
}
}
假设我想实现一个 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 种类型 E
和 E1
。
当更改为 static
方法时,您可以根据需要自由声明异常类型参数。您可以声明超类型异常类型 S
,然后是子类型异常类型 E1
和 E2
。然后其余的遵循类似于 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));
}
}