我想将函数的type参数限制为功能接口。
这样的事情:
public static <@FunctionalInterface T extends Function<A, B>> T foo () {
return a -> bar;
}
此处不允许@FunctionalInterface
。
目的是使得可以返回具有类型参数类型的lambda。由于T
可以是普通类,因此不允许返回lambda。
是否有可能将类型参数限制为功能接口?
答案 0 :(得分:6)
正如your other question已经讨论的那样,不可能这样做。不仅要注释类型参数,还要特别是通过lambda表达式实现未知接口。
编译方法时
public static <@FunctionalInterface T extends Function<A, B>> T foo() {
return a -> bar;
}
编译器必须生成能够返回相应类型实例的代码,但它不知道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);
}
此代码适用于未知类型A
和B
以及Map
的未知参数化,因为唯一的约束是方法Map.get
接受{{1}的实例它接受任何并返回A
的实例,因为任何类型B
都可以分配给? extends B
。
现在,如果您的来电者具有B
,Function
的任意子类型,例如
X
它可以使用您的工厂方法生成interface X extends Function<String, Integer> {}
的实例,其中修饰该函数,如:
X
此处,在呼叫者网站上检查Map<String, Integer> map=new HashMap<>();
X x=getter(map)::apply;
x.apply("foo");
作为功能接口的约束。
答案 1 :(得分:2)
我的仿制药很弱,但我认为那会是:
public static <T, R> Function<T, R> foo() {
// ...
}
但我认为你不能实例化 R
,你必须能够从T
获得它。您的代码不知道R
的运行时类型,因此new R()
超出范围。
但是,例如,如果T
可以为您提供R
,就像Map
一样:
public static <K, R, T extends Map<K,R>> Function<T, R> makeGetter(K key) {
return a -> a.get(key);
}
返回一个getter,当使用给定的map调用时,将返回带有用于创建getter的键的条目:
import java.util.function.Function;
import java.util.*;
public class Example {
public static final void main(String[] args) {
Map<String,Character> mapLower = new HashMap<String,Character>();
mapLower.put("alpha", 'a');
mapLower.put("beta", 'b');
Map<String,Character> mapUpper = new HashMap<String,Character>();
mapUpper.put("alpha", 'A');
mapUpper.put("beta", 'B');
Function<Map<String, Character>, Character> getAlpha = makeGetter("alpha");
System.out.println("Lower: " + getAlpha.apply(mapLower));
System.out.println("Upper: " + getAlpha.apply(mapUpper));
}
public static <K, R, T extends Map<K,R>> Function<T, R> makeGetter(K key) {
return a -> a.get(key);
}
}
输出:
Lower: a Upper: A
我不认为类型擦除会让你比这更接近,除非使用实例方法并参数化你的包含类。