How to negate a method reference predicate

JavaPredicateJava 8Negate

Java Problem Overview


In Java 8, you can use a method reference to filter a stream, for example:

Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();

Is there a way to create a method reference that is the negation of an existing one, i.e. something like:

long nonEmptyStrings = s.filter(not(String::isEmpty)).count();

I could create the not method like below but I was wondering if the JDK offered something similar.

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

Java Solutions


Solution 1 - Java

Predicate.not( … )

[tag: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();

Solution 2 - Java

I'm planning to static import the following to allow for the method reference to be used inline:

public static <T> Predicate<T> not(Predicate<T> t) {
    return t.negate();
}

e.g.

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

Update: Starting from Java-11, the JDK offers a similar solution built-in as well.

Solution 3 - Java

There is a way to compose a method reference that is the opposite of a current method reference. See @vlasec's answer below that shows how by explicitly casting the method reference to a Predicate and then converting it using the negate function. That is one way among a few other not too troublesome ways to do it.

The opposite of this:

Stream<String> s = ...;
int emptyStrings = s.filter(String::isEmpty).count();

is this:

Stream<String> s = ...;
int notEmptyStrings = s.filter(((Predicate<String>) String::isEmpty).negate()).count()

or this:

Stream<String> s = ...;
int notEmptyStrings = s.filter( it -> !it.isEmpty() ).count();

Personally, I prefer the later technique because I find it clearer to read it -> !it.isEmpty() than a long verbose explicit cast and then negate.

One could also make a predicate and reuse it:

Predicate<String> notEmpty = (String it) -> !it.isEmpty();

Stream<String> s = ...;
int notEmptyStrings = s.filter(notEmpty).count();

Or, if having a collection or array, just use a for-loop which is simple, has less overhead, and *might be **faster:

int notEmpty = 0;
for(String s : list) if(!s.isEmpty()) notEmpty++;

*If you want to know what is faster, then use JMH http://openjdk.java.net/projects/code-tools/jmh, and avoid hand benchmark code unless it avoids all JVM optimizations — see https://stackoverflow.com/questions/22658322/java-8-performance-of-streams-vs-collections

**I am getting flak for suggesting that the for-loop technique is faster. It eliminates a stream creation, it eliminates using another method call (negative function for predicate), and it eliminates a temporary accumulator list/counter. So a few things that are saved by the last construct that might make it faster.

I do think it is simpler and nicer though, even if not faster. If the job calls for a hammer and a nail, don't bring in a chainsaw and glue! I know some of you take issue with that.

wish-list: I would like to see Java Stream functions evolve a bit now that Java users are more familiar with them. For example, the 'count' method in Stream could accept a Predicate so that this can be done directly like this:

Stream<String> s = ...;
int notEmptyStrings = s.count(it -> !it.isEmpty());

or

List<String> list = ...;
int notEmptyStrings = lists.count(it -> !it.isEmpty());

Solution 4 - Java

Predicate has methods and, or and negate.

However, String::isEmpty is not a Predicate, it's just a String -> Boolean lambda and it could still become anything, e.g. Function<String, Boolean>. Type inference is what needs to happen first. The filter method infers type implicitly. But if you negate it before passing it as an argument, it no longer happens. As @axtavt mentioned, explicit inference can be used as an ugly way:

s.filter(((Predicate<String>) String::isEmpty).negate()).count()

There are other ways advised in other answers, with static not method and lambda most likely being the best ideas. This concludes the tl;dr section.


However, if you want some deeper understanding of lambda type inference, I'd like to explain it a bit more to depth, using examples. Look at these and try to figure out what happens:

Object obj1                  = String::isEmpty;
Predicate<String> p1         = s -> s.isEmpty();
Function<String, Boolean> f1 = String::isEmpty;
Object obj2                  = p1;
Function<String, Boolean> f2 = (Function<String, Boolean>) obj2;
Function<String, Boolean> f3 = p1::test;
Predicate<Integer> p2        = s -> s.isEmpty();
Predicate<Integer> p3        = String::isEmpty;
  • obj1 doesn't compile - lambdas need to infer a functional interface (= with one abstract method)
  • p1 and f1 work just fine, each inferring a different type
  • obj2 casts a Predicate to Object - silly but valid
  • f2 fails at runtime - you cannot cast Predicate to Function, it's no longer about inference
  • f3 works - you call the predicate's method test that is defined by its lambda
  • p2 doesn't compile - Integer doesn't have isEmpty method
  • p3 doesn't compile either - there is no String::isEmpty static method with Integer argument

I hope this helps get some more insight into how type inferrence works.

Solution 5 - Java

Building on other's answers and personal experience:

Predicate<String> blank = String::isEmpty;
content.stream()
       .filter(blank.negate())

Solution 6 - Java

Another option is to utilize lambda casting in non-ambiguous contexts into one class:

public static class Lambdas {
    public static <T> Predicate<T> as(Predicate<T> predicate){
        return predicate;
    }

    public static <T> Consumer<T> as(Consumer<T> consumer){
        return consumer;
    }

    public static <T> Supplier<T> as(Supplier<T> supplier){
        return supplier;
    }

    public static <T, R> Function<T, R> as(Function<T, R> function){
        return function;
    }

}

... and then static import the utility class:

stream.filter(as(String::isEmpty).negate())

Solution 7 - Java

Shouldn't Predicate#negate be what you are looking for?

Solution 8 - Java

In this case u could use the org.apache.commons.lang3.StringUtilsand do

int nonEmptyStrings = s.filter(StringUtils::isNotEmpty).count();

Solution 9 - Java

I have written a complete utility class (inspired by Askar's proposal) that can take Java 8 lambda expression and turn them (if applicable) into any typed standard Java 8 lambda defined in the package java.util.function. You can for example do:

  • asPredicate(String::isEmpty).negate()
  • asBiPredicate(String::equals).negate()

Because there would be numerous ambiguities if all the static methods would be named just as() , I opted to call the method "as" followed by the returned type. This gives us full control of the lambda interpretation. Below is the first part of the (somewhat large) utility class revealing the pattern used.

Have a look at the complete class here (at gist).

public class FunctionCastUtil {

    public static <T, U> BiConsumer<T, U> asBiConsumer(BiConsumer<T, U> biConsumer) {
        return biConsumer;
    }

    public static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> biFunction) {
        return biFunction;
    }

     public static <T> BinaryOperator<T> asBinaryOperator(BinaryOperator<T> binaryOperator) {
        return binaryOperator;
    }

    ... and so on...
}

Solution 10 - Java

You can use Predicates from Eclipse Collections

MutableList<String> strings = Lists.mutable.empty();
int nonEmptyStrings = strings.count(Predicates.not(String::isEmpty));

If you can't change the strings from List:

List<String> strings = new ArrayList<>();
int nonEmptyStrings = ListAdapter.adapt(strings).count(Predicates.not(String::isEmpty));

If you only need a negation of String.isEmpty() you can also use StringPredicates.notEmpty().

Note: I am a contributor to Eclipse Collections.

Solution 11 - Java

You can accomplish this as long emptyStrings = s.filter(s->!s.isEmpty()).count();

Solution 12 - Java

If you're using Spring Boot (2.0.0+) you can use:

import org.springframework.util.StringUtils;

...
.filter(StringUtils::hasLength)
...

Which does: return (str != null && !str.isEmpty());

So it will have the required negation effect for isEmpty

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionassyliasView Question on Stackoverflow
Solution 1 - JavaAnton BalaniucView Answer on Stackoverflow
Solution 2 - JavadavidillsleyView Answer on Stackoverflow
Solution 3 - JavaThe CoordinatorView Answer on Stackoverflow
Solution 4 - JavaVlasecView Answer on Stackoverflow
Solution 5 - JavaJose AlbanView Answer on Stackoverflow
Solution 6 - JavaAskar KalykovView Answer on Stackoverflow
Solution 7 - JavaMarco13View Answer on Stackoverflow
Solution 8 - JavaoutofBoundsView Answer on Stackoverflow
Solution 9 - JavaPer-Åke MinborgView Answer on Stackoverflow
Solution 10 - JavaNikhil NanivadekarView Answer on Stackoverflow
Solution 11 - JavaNarsi Reddy NallamilliView Answer on Stackoverflow
Solution 12 - JavaGilad PelegView Answer on Stackoverflow