在Java 8中返回泛型函数接口 [英] Return generic functional interface in Java 8

查看:606
本文介绍了在Java 8中返回泛型函数接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一种功能工厂。它应该是一个函数,它被称为一次不同的策略作为参数。它应该返回一个函数,该函数根据参数选择这个策略中的一个,这由谓词来实现。
那么,为了更好的理解,最好看看 condition3
问题是,它没有编译。我认为,因为编译器无法弄清楚,函数接口 H 可以通过实现来实现。
没有泛型,它工作正常。

  @FunctionalInterface 
public interface Finder< T,S> {

Stream< S> findBest(T t);

//有效代码
static< P,Q> Finder< P,Q> condition1(){
return p - >空值;
}

//有效的代码,但是当方法被调用时只选择其中一个H
static< P,Q,H扩展Finder< P,Q>> ; H条件2(Pair< Predicate< P>,H> ... hs){
return hs [0] .getRight();
}

//应该返回一个方法,当它用P
调用时,它会选择合适的H
// //编译器抱怨:
//该表达式的目标类型必须是功能接口
static< P,Q,H扩展Finder< P,Q>> H条件3(Pair< Predicate< P>,H> ... hs){
return p - > stream(hs).filter(pair - > pair.getLeft().test(p))
.findFirst()
.map(Pair :: getRight)
.map(h - > h.findBest(p))
。orElseGet(Stream :: empty);
}
}

那么这里有什么问题?我可以解决它,如果它可能与Java:如何?

解决方案

看看你的方法的签名,并试图告诉什么确切的返回类型是:

  static   

Lambdas只能实现界面在编译时已知,但编译器不知道 H 的实际类型参数。



你的第一个方法是可行的,因为它返回lambda可以实现的类型 Finder< P,Q> ,你的第二个方法可以工作,因为它不使用lambda来实现返回类型 H扩展Finder< P,Q>



只有第三种方法试图为类型指定lambda表达式参数 H扩展Finder< P,Q>






A解决方案并不是让调用者自由地将特定的 Finder 子类型作为方法的返回类型:

< $ P $ Q $> $ P $ Q $>静态< P,Q>条件3(Pair< Predicate< P>,H> ;. .. hs){






请看下面的例子:

  final class HImpl实现了Finder< String,String> {
public Stream< String> findBest(String t){
return null; //只是为了说明,我们从来没有真正使用过类
}
}

...

  HImpl x = Finder。< String,String,HImpl> condition3(); 

考虑到您的原始方法签名,这个编译没有任何错误。但是如何使用lambda表达式 condition3 在这里提供一个 HImpl 的实例?


I want to write kind of function factory. It should be a function, which is called once which different strategies as parameters. It should return a function, which selects one of this strategies dependent on the parameter, which is to be fulfilled by a predicate. Well, better look at condition3 for better understanding. The problem is, that it is not compiling. I think because the compiler can't figure out, that the functional interface H can be realized by the implementation. Without generics it is working fine.

@FunctionalInterface
public interface Finder<T, S> {

    Stream<S> findBest (T t);

    // Valid code
    static <P, Q> Finder<P, Q> condition1 () {
        return p -> null;
    }

    // Valid code, but selects just one of the H's when the method is invoked
    static <P, Q, H extends Finder<P, Q>> H condition2 (Pair<Predicate<P>, H>... hs) {
        return hs[0].getRight ();
    }

    // Should return a method, which selects the appropiate H 
    // whenever it is invoked with an P
    // Compiler complain: 
    // The target type of this expression must be a functional interface
    static <P, Q, H extends Finder<P, Q>> H condition3 (Pair<Predicate<P>, H>... hs) {
        return p -> stream (hs).filter (pair -> pair.getLeft ().test (p))
                               .findFirst ()
                               .map (Pair::getRight)
                               .map (h -> h.findBest (p))
                               .orElseGet (Stream::empty);
    }
}

So what's the problem here? Can I solve it and if it's possible with Java: how?

解决方案

Look at the signature of your method and try to tell what the exact return type is:

static <P, Q, H extends Finder<P, Q>> H condition3(…

Lambdas can only implement an interface known at compile-time. But the actual type argument for H is not known to the compiler.

Your first method works because it returns the type Finder<P, Q> which the lambda can implement, your second works because it doesn’t use a lambda for implementing the return type H extends Finder<P, Q>.

Only your third method attempts to specify a lambda expression for a type argument H extends Finder<P, Q>.


A solution is not to give the caller the freedom to mandate a particular sub-type of Finder as the method’s return type:

static <P, Q, H extends Finder<P, Q>>
    Finder<P, Q> condition3(Pair<Predicate<P>, H>... hs) {


To illustrate what implications your original method signature has, look at the following example:

final class HImpl implements Finder<String,String> {
    public Stream<String> findBest(String t) {
        return null; // just for illustration, we never really use the class
    }
}

HImpl x=Finder.<String,String,HImpl>condition3();

Given your original method signature this compiles without any error. But how ought the method condition3 provide an instance of HImpl here using your lambda expression?

这篇关于在Java 8中返回泛型函数接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆