How to Negate a Method Reference Predicate

How to negate a method reference predicate

Predicate.not( … )

java-11 offers a new method Predicate#not

So you can negate the method reference:

Stream<String> s = ...;
long nonEmptyStrings = s.filter(Predicate.not(String::isEmpty)).count();

How can I negate a lambda Predicate?

You would have to do .filter(((Predicate<String>) String::isEmpty).negate())

If you want, you can define

static<T> Predicate<T> not(Predicate<T> p) {
return t -> !p.test(t);
}

and then

.filter(not(String::isEmpty))

but I would just stick with v -> !v.isEmpty()

Create Predicate with and/or/negate methods in one statement?

Yes, you need to cast your lambda on Predicate type, where T is your type. Example with Person class.

Predicate<Person> a = ((Predicate<Person>)p -> p.getId() > 2)
.and(p -> p.getPrice() > 100);

How to chain PredicateT in filter() while using method references?

You can't do that because this:

Movie::titleFilter(titleFilter)

isn't really a method reference. You are kind of passing in a parameter, which seems to indicate that you want to call the method. But you are using ::, which makes it look like a method references.

If you just did Movie::titleFilter however, that would be a method reference, but it can't be converted to Predicate<Movie>. It could be converted to Function<String, Predicate<Movie>> if you had specified the type explicitly, but that's obviously not what you want.

Also note that even if you had two methods in Movie like this (these are both convertible to Predicate<Movie>):

public boolean predicate1() { ... }

public boolean predicate2() { ... }

You cannot or them like this:

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

Because Movie::predicate1 doesn't have a type in and of itself. This is to allow it to be converted to any functional interface with a compatible signature. You have to do:

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

instead.

What I think you intended is:

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

And:

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

Basically, to make a method reference, you can't pass parameters to it, and there's not such thing as "partial application" of a method in Java. (It'd be cool if it existed though...)

How to implement method reference as a predicate?

The someObj.getStringValue() expression is evaluated outside, so equivalent code would be:

final String x = someObject.getStringValue();
Predicate<String> p = new Predicate<String>() {
@Override
public boolean test(String t) {
return x.equalsIgnoreCase(t);
}
}
Stream.of("A", "B", "C").anyMatch(p)

where the local variable x is "anonymous" too.

Because of this, someObject does not need to be effectively final.

You can verify this behavior for the lambda expression in a debugger, by putting a breakpoint inside getStringValue(). Even though the test() method is called 3 times (because the stream has 3 elements, and assuming no match), the getStringValue() method will only be called once.

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

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, e.g. ((BiPredicate<String,String>)String::contains).negate(), but it’s much simpler to just negate the resulting predicate which has the same effect, e.g.

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

Using Predicate method - The target type of this expression must be a functional interface

What's the difference between String::isBlank and p?

p has a type. String::isBlank does not.

From the Java Language Specification, Type of a Method Reference,

A method reference expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived from T.

It then proceeds to define what "congruent" and "ground target type" means. The relevant part to your question is, String::isBlank is not in an assignment context, invocation context, or casting context, when you write it like this:

(String::isBlank).negate()

You might think this counts as an invocation context, but invocation contexts are actually the arguments of method calls, like someMethod(String::isBlank). As the spec says:

Invocation contexts allow an argument value in a method or constructor invocation (§8.8.7.1, §15.9, §15.12) to be assigned to a corresponding formal parameter.

Anyway, because String::isBlank is not in any of those contexts, the spec doesn't say anything about its type. In fact, just a bit up the page, it states,

It is a compile-time error if a method reference expression occurs in a program in someplace other than an assignment context (§5.2), an invocation context (§5.3), or a casting context (§5.5).

So those contexts turn out to be the only contexts that method references can occur in!

I didn't design the Java Language, so I can't tell you how the designers thought when they designed this, but I know that this design is rather simple to implement, compared to, say, allowing method references everywhere, which would require considering a lot more edge cases, and how this would interact with other language features. If method references are just limited to these three contexts, there won't be as much edge cases to consider, and it's relatively easy to figure out what types they are, and if you want to use them in a random expression somewhere, this design also allows you to do that just by casting:

((Predicate<String>)String::isBlank).negate()

It's a fairly good compromise, in my opinion.

If you are still wondering "why didn't they implement it like ... instead?" I recommend checking out Eric Lippert's answer here.



Related Topics



Leave a reply



Submit