1

I often check if a collection contains an element during stream operations and I write code like this:

Set<String> users = ...
Set<String> unemployed = ...

users.stream().filter(unemployedUsers::contains)

But I also need to check NOT condition, then I have to write something like this:

users.stream().filter(user -> !unemployedUsers.contains(user))

which looks less readable and a bit ugly.

It would be great if I could replace it with something like this:

users.stream().filter(not(unemployedUsers::contains))

But I haven't found any API in standard lib that allows this.

Q: How can I replace lambda expression with method reference when I need to check NOT condition? Or is there any other way that would do the same but in more elegant way?

UPDATE: This question duplicates "How to negate a method reference predicate". However is more about how to write NOT operation in more readable/elegant way.

I can write custom code like this

Predicate<String> not(Predicate<String> predicate) {
    return predicate.negate();
}

And use the construction with not(unemployedUsers::contains), but there might be someone who solves this problem in better way.

Sasha Shpota
  • 9,436
  • 14
  • 75
  • 148
  • 3
    FYI, [JDK-8050818](https://bugs.openjdk.java.net/browse/JDK-8050818) covers the addition of a static `Predicate.not(Predicate)` method. But that issue is still open so we'll see this at the earliest in Java 12 (if ever). – Stefan Zobel Jan 15 '18 at 15:45
  • @StefanZobel with the new release cycle it should be available in quite short time. JDK 10 is getting released in March 2018, theoretically 12 will be available in 2019. – Sasha Shpota Jan 15 '18 at 16:05
  • @StefanZobel please post this as an answer - I'll accept. – Sasha Shpota Jan 15 '18 at 16:06
  • Uups, sorry. I meant Java 11 - not 12. Java 10 is already in rampdown phase, so it's quite unlikely that this will get in. – Stefan Zobel Jan 15 '18 at 16:19

3 Answers3

3

Not so nicely as you might like. The argument to a filter is a Predicate, and Predicate does have a negate() method. But in order to use it, you would need to cast your argument to a Predicate.

filter(((Predicate<String>) unemployedUsers::contains).negate())

You're probably better off with

filter(u -> !unemployedUsers.contains(u))
khelwood
  • 55,782
  • 14
  • 81
  • 108
1

You can't without an explicit cast:

((Predicate<String>) unemployedUsers::contains).negate())

that is because the method reference can potentially be applied to more things, not just Predicate<String> (could be a Function<String, Boolean>)

Eugene
  • 117,005
  • 15
  • 201
  • 306
1

There is no way. You need to cast the object to the desired class like this:

((Predicate<String>) unemployedUsers::contains).negate();
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193