简体   繁体   English

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

[英]Mark generic type parameter as functional interface in Java 8

I want to restrict the type parameter of a function to be a functional interface. 我想将函数的类型参数限制为功能接口。

Something like this: 像这样的东西:

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

The @FunctionalInterface is not allowed here. 这里不允许使用@FunctionalInterface

The aim is, to make it possible to return a lambda with the type of the type parameter. 目的是使得可以返回具有类型参数类型的lambda。 Since T can be a normal class, a return of a lambda is not allowed. 由于T可以是普通类,因此不允许返回lambda。

Is there a possibility to restrict the type parameter to be a functional interface? 是否有可能将类型参数限制为功能接口?

As already discussed on your other question it is impossible to do that. 正如您在其他问题上已经讨论过的那样,这是不可能的 Not only annotating the type parameter but especially implementing an unknown interface via lambda expression. 不仅要注释类型参数,还要特别是通过lambda表达式实现未知接口。

When compiling your method 编译方法时

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

the compiler must produce code capable of returning an instance of the appropriate type but it doesn't know what T will be as this depends on the caller of foo() but there is no connection between compiling foo() and compiling the caller of foo() . 编译器必须生成能够返回适当类型的实例的代码,但它不知道T将是什么,因为这取决于foo()的调用者,但编译foo()和编译foo()的调用者之间没有任何联系foo() The latter might happen years later on the other side of the our planet. 后者可能在几年之后发生在我们这个星球的另一边。

Maybe you are not aware of Type Erasure . 也许你不知道Type Erasure There will be only one compiled version of your method foo() but it has to fulfill the generic contract of returning an instance of the appropriate type. 您的方法foo()只有一个编译版本,但它必须满足返回适当类型实例的通用协定。 Without knowing what T is . 不知道 T 什么

This works when returning an existing instance like when returning an element of a collection or one of the values passed as parameters. 这在返回现有实例时有效,例如返回集合的元素或作为参数传递的值之一。 But generic methods are unable to return new instances of a type parameter. 但是泛型方法无法返回类型参数的新实例。 Not using new and neither using a lambda expression. 不使用new ,也不使用lambda表达式。


Note that it is still possible to have sub-interface implementations of the desired function if you let the caller which knows the type perform the “up-level” operation. 请注意,如果让知道类型的调用者执行“up-level”操作,仍然可以使用所需函数的子接口实现。 Suppose the you have a Generic factory method like: 假设你有一个Generic工厂方法,如:

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

This code works with the unknown types A and B and the unknown parametrization of Map because the only constraint is the method Map.get accepts instances of A which it does as it accepts anything and returns an instance of B which it does as any type ? extends B 这段代码适用于未知类型AB以及Map的未知参数化,因为唯一的约束是方法Map.get接受它的A实例,因为它接受任何东西并返回它做任何类型的B实例? extends B ? extends B will be assignable to B . ? extends B将可分配给B

Now, if your caller has an arbitrary sub-type of Function , X , eg 现在,如果你的调用者有一个任意子类型的FunctionX ,例如

interface X extends Function<String, Integer> {}

it can use your factory method to produce an instance of X which decorates the function, like: 它可以使用你的工厂方法来生成一个装饰函数的X实例,如:

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

Here, the constraint on X being a functional interface is checked on the caller site. 这里,在调用者站点上检查对作为功能接口的 X的约束。

My generics-fu is weak, but I think that would be: 我的仿制药很弱,但我认为这将是:

public static <T, R> Function<T, R> foo() {
    // ...
}

But I don't think you can instantiate R , you'd have to be able to get it from T . 但是我认为你不能实例化 R ,你必须能够从T获得它。 Your code doesn't know the runtime type of R , so new R() is out of bounds. 您的代码不知道R的运行时类型,因此new R()超出范围。

But for example, if T can give you R , as with a Map : 但是,例如,如果T可以给你R ,就像Map

public static <K, R, T extends Map<K,R>> Function<T, R> makeGetter(K key) {
    return a -> a.get(key);
}

That returns a getter that, when called with a given map, will return the entry with the key you used to create the getter: 返回一个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);
    }
}

Output: 输出:

Lower: a
Upper: A

I don't think type erasure lets you get much closer than that, barring using an instance method and parameterizing your containing class. 我认为类型擦除不会让你比这更接近,除非使用实例方法和参数化你的包含类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM