简体   繁体   中英

Passing a function into the Stream's filter method in Java 8

I want to filter a list using String methods reference on the streamed object, for that I created the following compare function:

<V, C, P> Predicate<? super P> compare(Function<P, V> valueFunction, BiPredicate<V, C> matchPredicate, C value) {
    return p -> matchPredicate.test(valueFunction.apply(p), value);
}

And a call to that method look like this:

.filter(compare(Utilisateur::getIndividuIde, String::contains, libelleFilter.getFilterSingleValue().toUpperCase()))

This is the function where I filter the list depending on the given filter mode:

public List<Utilisateur> listUtilisateur(FilterDTO libelleFilter) {
    List<Utilisateur> list = utilisateurDAO.listUtilisateur();

    switch (libelleFilter.getOperator()) {
    case TEXT_CONTAINS:
        list = list.stream()
                .filter(compare(Utilisateur::getIndividuIde, String::contains, libelleFilter.getFilterSingleValue().toUpperCase()))
                .collect(Collectors.toList());
        break;
    case TEXT_START_WITH:
        list = list.stream()
                .filter(compare(Utilisateur::getIndividuIde, String::startsWith, libelleFilter.getFilterSingleValue().toUpperCase()))
                .collect(Collectors.toList());
        break;
    case TEXT_DIFFERENT:
        list = list.stream()
                .filter(compare(Utilisateur::getIndividuIde, String::, libelleFilter.getFilterSingleValue().toUpperCase()))
                .collect(Collectors.toList());
        break;
    case TEXT_END_WITH:
        list = list.stream()
                .filter(compare(Utilisateur::getIndividuIde, String::endsWith, libelleFilter.getFilterSingleValue().toUpperCase()))
                .collect(Collectors.toList());
        break;
    case TEXT_EQUALS:
        list = list.stream()
                .filter(compare(Utilisateur::getIndividuIde, String::equals, libelleFilter.getFilterSingleValue().toUpperCase()))
                .collect(Collectors.toList());
        break;
    default:
        break;
    }
    return list;

}

So the problem I'm facing here is that I don't want to compare the Utilisateur::getIndividuIde value this is just an information for the real string I want to compare which I get using the following :

Individu individu = individuLightSVC.donneIndividu(utilisateur.getIndividuIde(), null);
String stringToCompare = individu.getPrenom() + " " + individu.getNom()

So in the compare function I've created, I need something like this :

private <V, C, P> Predicate<? super P> compare(Function<P, V> valueFunction, BiPredicate<V, C> matchPredicate, C value) {
    // Here I want to replace X with the string value of Utilisateur::getIndividuIde 
    Individu individu = individuLightSVC.donneIndividu(X, null);

    String stringToCompare = individu.getPrenom() + " " + individu.getNom();

    // Here I want to use stringToCompare instead of valueFunction.apply(p)
    return p -> matchPredicate.test(valueFunction.apply(p), value);
}

Another issue I'm facing is how to negate the method reference predicate String::contains since String has no notContains function, you can see that I left it empty in this line : .filter(compare(Utilisateur::getIndividuIde, String::, libelleFilter.getFilterSingleValue().toUpperCase()))

Would you help me? I would appreciate any help.

Solution for the second issue:

Thanks to @Holger comment, the negation on String::contains can be done by negating the predicate I get from compare function :

.filter(compare(Utilisateur::getIndividuIde, String::contains, libelleFilter.getFilterSingleValue().toUpperCase()).negate())

You can't use a type parameter, when the type is supposed to be a String . So just drop <V> and use String . Then, the code you have written into the method has to be placed inside the lambda expression to be executed each time the function is evaluated:

private <C, P> Predicate<P> compare(
    Function<P, String> valueFunction,
    BiPredicate<? super String, C> matchPredicate, C value) {

    return p -> {
        Individu individu = individuLightSVC.donneIndividu(valueFunction.apply(p), null);
        String stringToCompare = individu.getPrenom() + " " + individu.getNom();
        return matchPredicate.test(stringToCompare, value);
    };
}

Negating can be done using, eg ((BiPredicate<String,String>)String::contains).negate() , but it's much simpler to just negate the resulting predicate which has the same effect, eg

.filter(compare(Utilisateur::getIndividuIde, String::contains,
        libelleFilter.getFilterSingleValue().toUpperCase()).negate()‌​)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM