如何在使用方法引用时在 filter() 中链接 Predicate<T>?

How to chain Predicate<T> in filter() while using method references?

我有一个 class 电影是这样的:

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());
    }

}

如何在使用方法引用时链接 Predicate 过滤器?我知道对于只调用特定方法的 lambda,方法引用可以被视为 shorthand。在我正在阅读的书中,它说:“......方法参考让你从现有的方法实现中创建一个 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());
    }

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

你不能那样做,因为:

Movie::titleFilter(titleFilter)

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

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

另请注意,即使您在 Movie 中有两个像这样的方法(它们都可以转换为 Predicate<Movie>):

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中没有方法"partial application"。 (不过要是有就好了...)