将泛型类型参数标记为Java 8中的功能接口

F. *_*ler 4 java generics lambda java-8 java-stream

我想将函数的类型参数限制为功能接口.

像这样的东西:

public static <@FunctionalInterface T extends Function<A, B>> T foo () {
    return a -> bar;
}
Run Code Online (Sandbox Code Playgroud)

@FunctionalInterface这里不允许使用.

目的是使得可以返回具有类型参数类型的lambda.由于T可以是普通类,因此不允许返回lambda.

是否有可能将类型参数限制为功能接口?

Hol*_*ger 6

正如您在其他问题上已经讨论过的那样,这是不可能的.不仅要注释类型参数,还要特别是通过lambda表达式实现未知接口.

编译方法时

public static <@FunctionalInterface T extends Function<A, B>> T foo() {
    return a -> bar;
}
Run Code Online (Sandbox Code Playgroud)

编译器必须生成能够返回适当类型的实例的代码,但它不知道T将是什么,因为这取决于调用者,foo()但编译foo()和编译调用者之间没有连接foo().后者可能在几年之后发生在我们这个星球的另一边.

也许你不知道Type Erasure.您的方法只有一个编译版本,foo()但它必须履行返回适当类型实例的通用协定.不知道什么 T .

这在返回现有实例时有效,例如返回集合的元素或作为参数传递的值之一.但是泛型方法无法返回类型参数的新实例.不使用new也不使用lambda表达式.


请注意,如果让知道类型的调用者执行"up-level"操作,仍然可以使用所需函数的子接口实现.假设你有一个Generic工厂方法,如:

public static <A,B> Function<A,B> getter(Map<?, ? extends B> map) {
    return a->map.get(a);
}
Run Code Online (Sandbox Code Playgroud)

这段代码适用于未知类型AB未知参数化,Map因为唯一的约束是该方法Map.get接受A它所做的实例,因为它接受任何东西并返回B它所做的实例,因为任何类型? extends B都可以分配给它B.

现在,如果您的来电者有一个任意的分型Function,X

interface X extends Function<String, Integer> {}
Run Code Online (Sandbox Code Playgroud)

它可以使用你的工厂方法生产的实例X,其装饰功能,如:

Map<String, Integer> map=new HashMap<>();
X x=getter(map)::apply;
x.apply("foo");
Run Code Online (Sandbox Code Playgroud)

这里,在调用者站点上检查X作为功能接口的约束.

  • @TJ Crowder:问题在于:"匹配Foo和Foo的任何子类型"意味着,调用者可以用他希望的子类型Foo替换该类型.在这种情况下,你返回的`Function`必须返回Foo的子类型,但你无法实现,因为`Map`的保证是返回Foo. (2认同)