assylias
assylias

Reputation: 328568

How to negate a method reference predicate

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

Upvotes: 503

Views: 266326

Answers (14)

outofBounds
outofBounds

Reputation: 691

In this case, you could use org.apache.commons.lang3.StringUtils and do

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

Upvotes: 9

Vlasec
Vlasec

Reputation: 5547

On type inference

Predicate has default methods and, or and negate.

However, String::isEmpty is not a Predicate. It could also be Function<String, Boolean>. Without type inference, there is no way to know its functional interface.

If Java had filterNot method (hint: it doesn't), there could be a nice implicit inference:

s.filterNot(String::isEmpty).count()

Negation by instance method (as mentioned by @axtavt) involves explicit inference:

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

It is rather unsightly. From code clarity point of view, implicit inference generally looks much better, even if it makes compiler's work a little more complicated.

Moreover, method reference isn't a unique identifier of a method. E.g. String::substring refers to both methods of the same name. Due to method overloading, it is unclear which method it refers to. This shows there is a lot of ambiguity that needs to be cleared.


Before we continue, look at these examples and figure out what happens (last two use Java 11):

Predicate<String> p1         = /*0*/ s -> s.isEmpty();
Function<String, Boolean> f1 = /*1*/ String::isEmpty;
Object o1                    = /*2*/ String::isEmpty;
Object o2                    = /*3*/ p1;
Function<String, Boolean> f2 = /*4*/ (Function<String, Boolean>) o2;
Function<String, Boolean> f3 = /*5*/ p1::test;
Predicate<Integer> p2        = /*6*/ s -> s.isEmpty();
Predicate<Integer> p3        = /*7*/ String::isEmpty;
var v1                       = /*8*/ Predicate.not(String::isEmpty);
var v2                       = /*9*/ Predicate.not(s -> s.isEmpty());

Let's analyze these examples:

  1. The lambda infers all its type information from p1 variable in assignment (=). That also infers that it's actually String s, and since String has instance method named isEmpty with no arguments and correct output type, it compiles.

  2. The method reference also infers its type information from f1 variable in assignment. That also infers the arguments and their types. There is only one matching method in String.

  3. The method reference fails to infer a functional interface from o1, Object is a class.

  4. Just a simple (if perhaps silly) down-casting of a Predicate to Object o2.

  5. The right operand of assignment is an expression that attempts to cast a Predicate that is stored in variable of Object type, as a Function f2. Exception is thrown at runtime.

  6. The method reference refers to an instance method of p1. Functional interface and arguments of said method are inferred from f3 variable, and there is a match.

    Effectively, this is a Function<String, Boolean> wrapper to a Predicate<String>.

  7. The lambda infers the functional interface and arguments from p3. The compiler looks for an instance method called isEmpty with no arguments in Integer, but there is no such thing.

  8. The method reference infers functional interface. It also infers Integer as input argument and Boolean as result type. This rules out instance methods of String (that would require first argument to be of type String rather than Integer). There is no static method String.isEmpty(Integer) either, so a compiler error occurs.

  9. By using var, v1 is still strongly typed at compile time, but the inference in the assignment (=) goes from right to left this time.

    The right operand calls static method not which has one argument, Predicate<T>. Method reference can infer input arguments count (1) and return type (boolean). One such method exists in String and its input type is String, so method not can infer String for <T>.

  10. Similarly, v2 is a mere consumer here. However, the lack of type information in the lambda results in compiler error as it's unclear what is the type of s. Perhaps List<BigDecimal>?


Now that it's clear how it works, let's revisit Predicate.not. As others mentioned, it was added in Java 11. If you want a cleaner look, especially if you negate multiple predicates in the same class, you might as well go for static import and have a result like this:

s.filter(not(String::isEmpty))

The static import however has its own downside: Adding another not method that negates something vaguely similar will result in ambiguity that you will need to resolve for your code to compile. The ambiguity is further aggravated by type erasure.

So, it all comes back to the fan favorite, a lambda negated by ! operator. This allows the lambda to infer its type directly from the filter method and it doesn't look too bad.

s.filter(s -> !s.isEmpty)

(unless you've developed in some newer language like Scala, Kotlin ...)

Summed up, functional paradigm in Java could look and feel better, so pick your poison.

Upvotes: 100

TWiStErRob
TWiStErRob

Reputation: 46460

Since this ranks highest on Google for Kotlin too ("kotlin negate function reference"), I'll post an answer here:

import kotlin.reflect.KFunction1

/**
 * Kotlin version of [java.util.function.Predicate.negate] for functional types.
 *
 * Example:
 * ```
 * val isX: X -> Boolean = ...
 * val isNotX = !isX
 * val isNotX = isX.not()
 * ```
 */
operator fun <T> ((T) -> Boolean).not(): (T) -> Boolean =
    { !this(it) }

/**
 * Kotlin version of [java.util.function.Predicate.negate] for method references.
 *
 * Example:
 * ```
 * fun isX(x: X): Boolean = ...
 * val isNotX = !::isX
 * ```
 */
operator fun <T> KFunction1<T, Boolean>.not(): KFunction1<T, Boolean> =
    { it: T -> !this(it) }::invoke

/**
 * Kotlin version of [java.util.function.Predicate.or] for functional types.
 */
infix fun <T> ((T) -> Boolean).or(other: (T) -> Boolean): (T) -> Boolean =
    { this(it) || other(it) }

/**
 * Kotlin version of [java.util.function.Predicate.or] for method references.
 */
infix fun <T> KFunction1<T, Boolean>.or(other: KFunction1<T, Boolean>): KFunction1<T, Boolean> =
    { it: T -> this(it) || other(it) }::invoke

/**
 * Kotlin version of [java.util.function.Predicate.and] for functional types.
 */
infix fun <T> ((T) -> Boolean).and(other: (T) -> Boolean): (T) -> Boolean =
    { this(it) && other(it) }

/**
 * Kotlin version of [java.util.function.Predicate.and] for method references.
 */
infix fun <T> KFunction1<T, Boolean>.and(other: KFunction1<T, Boolean>): KFunction1<T, Boolean> =
    { it: T -> this(it) && other(it) }::invoke

I'm not aware these being in stdlib, maybe they exist in some library already. Hope this helps someone in the future as the syntax was non-trivial to come up with.

Upvotes: -2

gomn
gomn

Reputation: 141

Tip: to negate a collection.stream().anyMatch(...), one can use collection.stream().noneMatch(...)

Upvotes: 2

Anton Balaniuc
Anton Balaniuc

Reputation: 11739

Predicate.not( … )

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

Upvotes: 463

davidillsley
davidillsley

Reputation: 2690

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.

Upvotes: 253

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

Upvotes: 1

Gilad Peleg
Gilad Peleg

Reputation: 2010

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

Upvotes: 0

The Coordinator
The Coordinator

Reputation: 13137

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

Upvotes: 165

Nikhil Nanivadekar
Nikhil Nanivadekar

Reputation: 1152

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.

Upvotes: 4

Per-&#197;ke Minborg
Per-&#197;ke Minborg

Reputation: 290

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...
}

Upvotes: 4

Askar Kalykov
Askar Kalykov

Reputation: 2581

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

Upvotes: 18

Jose Alban
Jose Alban

Reputation: 7926

Building on other's answers and personal experience:

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

Upvotes: 52

Marco13
Marco13

Reputation: 54611

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

Upvotes: 12

Related Questions