【问题标题】:How to chain Predicate<T> in filter() while using method references?使用方法引用时如何在 filter() 中链接 Predicate<T>?
【发布时间】:2019-11-28 21:30:23
【问题描述】:

我有一个像这样的类电影:

public class Movie {    
    private int id, duration, publishingYear;
    private String title, translation;


    public Movie(int id, int duration, int publishingYear, String title, String translation) {
        super();
        this.id = id;
        this.duration = duration;
        this.publishingYear = publishingYear;
        this.title = title;
        this.translation = translation;
    }

    public Predicate<Movie> titleFilter(String filter){
        return m -> m.getTitle().toLowerCase().contains(filter.toLowerCase());
    }

    public Predicate<Movie> translationFilter(String filter){
        return m -> m.getTranslation().toLowerCase().contains(filter.toLowerCase());
    }

}

如何在使用方法引用时链接谓词过滤器?我知道方法引用可以看作是 lambdas 仅调用特定方法的简写。在我正在阅读的书中,它说:“...方法参考让您可以从现有方法实现中创建 lambda 表达式...”。那么,为什么我不能这样做呢?

ArrayList<Movie> filteredMovies = (ArrayList<Movie>) app.getMovies().stream()
                .filter((Movie::titleFilter(titleFilter)).or(Movie::translationFilter(translationFilter)))
                .collect(Collectors.toList());

我知道这会起作用:

Predicate<Movie> titlePredicate = ( m -> m.getTitle().toLowerCase().contains(titleFilter)); 

Predicate<Movie> translationPredicate = ( m -> m.getTitle().toLowerCase().contains(translationFilter)); 

ArrayList<Movie> filteredMovies = (ArrayList<Movie>) app.getMovies().stream()
                                    .filter(titlePredicate.or(translationPredicate))
                                    .collect(Collectors.toList());

还有这个(只需插入 filter() ):

public boolean tFilter(String filter){
        return this.getTranslation().toLowerCase().contains(filter.toLowerCase());
    }

我最近开始使用 lambdas 和 Stream API。在我们大学的课程中,没有提到流。所以我认为我自己开始。新手。

【问题讨论】:

    标签: java lambda filter java-stream predicate


    【解决方案1】:

    你不能这样做,因为:

    Movie::titleFilter(titleFilter)
    

    并不是真正的方法参考。您是在传递一个参数,这似乎表明您要调用该方法。但是您使用的是::,这使它看起来像一个方法引用。

    如果你只是做了Movie::titleFilter,那将是一个方法引用,但它不能转换为Predicate&lt;Movie&gt;。如果您明确指定了类型,它可以转换为Function&lt;String, Predicate&lt;Movie&gt;&gt;,但这显然不是您想要的。

    还要注意,即使您在 Movie 中有两个这样的方法(这些都可以转换为 Predicate&lt;Movie&gt;):

    public boolean predicate1() { ... }
    
    public boolean predicate2() { ... }
    

    你不能像这样or他们:

    Movie::predicate1.or(Movie::predicate2)
    

    因为Movie::predicate1 本身没有类型。这是为了允许将其转换为具有兼容签名的任何功能接口。你必须这样做:

    ((Predicate<Movie>)Movie::predicate1).or(Movie::predicate2)
    

    改为。

    我认为你的意图是:

    // note the static modifiers
    public static Predicate<Movie> titleFilter(String filter){
        return m -> m.getTitle().toLowerCase().contains(filter.toLowerCase());
    }
    
    public static Predicate<Movie> translationFilter(String filter){
        return m -> m.getTranslation().toLowerCase().contains(filter.toLowerCase());
    }
    

    还有:

    // note that I am calling the methods which *return* a Predicate<Movie>
    ArrayList<Movie> filteredMovies = (ArrayList<Movie>) app.getMovies().stream()
                    .filter((Movie.titleFilter(titleFilter)).or(Movie.translationFilter(translationFilter)))
                    .collect(Collectors.toList());
    

    基本上,要进行方法引用,不能向其传递参数,Java 中也不存在方法的“部分应用”。 (如果它存在就好了……)

    【讨论】:

    • “因为 Movie::predicate1 本身没有类型”。你是想说这行不通吗,因为 predicate1() 不代表 Functional Interface 的“实例”,也就是说,它不是 lambda?
    • @MiljanPuletic 你的措辞有点不同,但我想你明白了。基本上,我可以创建自己的功能接口interface Foo { boolean f(Movie m); }Movie::predicate1 也可以转换为Foo,不是吗?这就是方法引用本身没有类型的原因。 Lambda 本身也没有类型。它们的类型是在您提供给编译器的线索的帮助下推断出来的。
    • 如果我是正确的(你会纠正我的),它可以,但前提是 predicate1() 返回的 lambda 与 Foo 接口中的功能描述符具有相同的签名。是的,我的措辞很烂:)
    • @MiljanPuletic 这与方法返回的 lambda 无关,而与方法的整个签名有关。 Movie::predicate1 始终可以转换为 Foo,因为它接受电影作为参数并返回一个布尔值,它符合 Foo 的要求。同时,它可以转换为Predicate&lt;Movie&gt;,因为它们的签名也匹配。这就是我说方法引用和 lambda 本身没有类型的原因。
    • 谢谢清扫教授。我知道更好理解。
    猜你喜欢
    • 1970-01-01
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 2010-10-14
    • 2010-10-18
    • 1970-01-01
    • 2015-05-08
    相关资源
    最近更新 更多