Is there a way to generify lambda?

时间:2019-04-08 13:00:34

标签: java generics lambda

I'm trying to write a lambda that will implement a @FunctionalInterface (BiFunction in this example) and will return an object generified with <T>.

I can do it with the old approach declaring a generified class (see class Extractor<T>), but I do not understand how to do it with lambda. The only thing I am able to do is to declare a lambda with "unknown" <?> generic type.

Basically, I want to declare a lambda that is possible to pass to method2. Is it possible?

private BiFunction<String, Root<Employee>, Path<?>> extractorLambda = 
    (fieldName, root) -> root.get(fieldName);

class ExtractorClass<T> implements BiFunction<String, Root<Employee>, Path<T>> {
    @Override
    public Path<T> apply(final String fieldName, final Root<Employee> root) {
        return root.get(fieldName);
    }
}

private Specification<Employee> method1(String fieldName,
                                        BiFunction<String, Root<Employee>, Path<?>> extractor) {
    return null;
}

private <T> Specification<Employee> method2(String fieldName,
                                            BiFunction<String, Root<Employee>, Path<T>> extractor) {
    return null;
}


public void main(String[] args) {
    method1("s", extractorLambda); // ok
    method2("s", extractorLambda); // error
    ExtractorClass<String> extractorClass = new Extractor<>();
    method2("s", extractorClass);               // ok
}

1 个答案:

答案 0 :(得分:1)

The problem is difference between <T> and <?>.

Your method2 expects List of objects of one type. <?> is unbounded wildcard that means it can contain whatever as long as it extends Object.

Same applies in other direction. If you try to use your Extractor class with method1, it won't compile because class says it works just for lists of certain type.

As far as I know you can't have generic type definition on field. Based on your comment this looks like shortest workaround:

    private interface E2<T> extends BiFunction<String, Root<Employee>, Path<T>>{}
    private static final E2 EXTRACTOR = (fieldName, root) -> root.get(fieldName);