在 Java8 中使用谓词实现过滤器<T>



为了掌握Java8,我正在尝试实现一个简单的Repo来存储不同对象的列表。

我的出发点是:

public class MyRepo {
    Map<Class, List<?>> repo =new HashMap<>();
    public List<?> get(Class c){
        List<?> result= repo.get(c);
        return (result==null)?new ArrayList<>():(List<?>) result;
    }
    public void put(Class c,List<?> l){
        repo.put(c, l);
    }
}    

所以我能够插入列表和检索列表。

我的下一步将是实现一个通用的过滤器方法:

public List<?> find(Class c, Predicate<?> predicate){
    List<?> result= repo.get(c);
    return (result==null)?new ArrayList<>():(List<?>)result.stream().filter(predicate);
}

结果是

java: incompatible types: java.util.function.Predicate<capture#1 of ?> cannot be converted to java.util.function.Predicate<? super capture#2 of ?>

如何实现一个通用的查找方法?

我必须承认,我不确定,设计

Map<Class, List<?>> repo =new HashMap<>();

是一个很好的选择。也许有更好的办法

首先你应该让你的方法泛型,这将让编译器决定你传递的是哪个Predicate,并据此推断一个特定的类型。同样,result.stream().filter(predicate)会得到Stream而不是List。您需要在List中收集流。

此外,由于您已经有了get(Class<T>)方法,您可以使用它而不是在find()方法中执行repo.get(c)方法。你也可以在这里使用java.util.Optional class:

Map<Class, List<?>> repo =new HashMap<>();
public <T> List<T> get(Class<T> c){
    return Optional.ofNullable((List<T>)repo.get(c)).orElse(new ArrayList<>());
}
public <T> void put(Class<T> c,List<T> l){
    repo.put(c, l);
}
public <T> List<T> find(Class<T> c, Predicate<T> predicate){
    return get(c).stream().filter(predicate).collect(Collectors.toList());
}

您需要修复您的方法签名。泛型通配符类型本质上是独立的——Java编译器没有理由相信一个?类型与另一个?类型有任何关系。

试题:

public <T> List<T> get(Class<T> c)
public <T> void put(Class<T> c, List<T> list)
public <T> List<T> find(Class<T> c, Predicate<T> predicate)

这个可配置的<T>参数允许调用者指定他们想要的任何类型,但也让编译器知道"嘿,这个List<T>Predicate<T> ?这是相同的T,所以你完全可以过滤

最新更新