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
andp
?
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
ifT
is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived fromT
.
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
Java Simpledateformat for Time Zone with a Colon Separator
Java: How to Access Methods from Another Class
Spring Boot How to Hide Passwords in Properties File
Where Should I Put the Log4J.Properties File
Combine Multiple Collections into a Single Logical Collection
Calculating All of the Subsets of a Set of Numbers
How to Scale Threads According to CPU Cores
Create a Autocompleting Textbox in Java with a Dropdown List
How to Limit Setaccessible to Only "Legitimate" Uses
Spring MVC - How to Return Simple String as JSON in Rest Controller
The Simplest Way to Comma-Delimit a List
Spring Data JPA - "No Property Found for Type" Exception
Is There a Java Utility to Do a Deep Comparison of Two Objects
Handling Soft-Deletes with Spring JPA
In Java, Is It More Efficient to Use Byte or Short Instead of Int and Float Instead of Double
How to Maintain Bi-Directional Relationships with Spring Data Rest and JPA
When Should We Create Our Own Java Exception Classes
Java "Lambda Expressions Not Supported at This Language Level"