Has it been considered to add inverse methods to collections which are in Optional?

Stuart Marks stuart.marks at oracle.com
Fri Dec 18 05:31:34 UTC 2020



On 12/8/20 5:30 AM, Remi Forax wrote:
>> De: "Dave Franken" <dwfranken at gmail.com>
> Adding methods like notContains or notFilter have been considered several times in the past and rejected because it's too many methods with no real gain. I'm sure you can dig some old emails on lambda-dev and see the first iteration of the Stream API, it was full of convenient methods like that.
> I'm sure Stuart or Brian have a template answer for that :)

Well I don't have a template handy but I can explain some of the reasoning. :-)

In general we try to avoid adding to many pure "convenience" methods that do things 
that are easily expressed other ways, e.g., through composition of existing methods 
or Java language constructs.

There are many boolean-returning methods in the JDK and we've tried to avoid 
defining methods that are simply inverses of each other. The notable exceptions are 
Objects.isNull and Objects.nonNull, which seemed sensible at the time, since 
references being null or non-null is quite fundamental to Java programming. (Note 
that these are mostly useful only as method references.)

Optional was introduced with isPresent, but without an inverse. Since Optional is 
(mostly) about having or not-having something, we later somewhat reluctantly added 
isEmpty, on the basis that the empty/present state of an Optional is as fundamental 
as null/non-null references.

Another common place where inverse methods have been requested is String. We've held 
off doing that. String has isEmpty and isBlank, which have different semantics, so 
this would naturally lead to having nonEmpty and nonBlank. There are also several 
other boolean-returning methods on String, so you can start to see how this could 
lead toward excessive method proliferation.

>> It would improve readability where we have the negation of isEmpty(), e.g.:
>>
>> if (!myList.isEmpty()) {
>> }

You might or might not like this syntax, but if you don't, adding new APIs here and 
there won't really solve anything.

Personally I think adding a space after ! makes the negation stand out a bit more 
(and I'm used to this) so it doesn't bother me:

     if (! myList.isEmpty()) { ...

One place where negation of a predicate does have a fairly high cost is with method 
references. If I have a stream where I want to filter for empty collections I could 
write

     filter(Collection::isEmpty)

which is fairly nice, but if I want to filter for non-empty collections, I have to 
convert it to a lambda:

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

This is mitigated by the addition of a Predicate.not method, which when statically 
imported, allows rewriting thus:

     filter(not(Collection::isEmpty))

This enables using method references in a bunch of places where they couldn't be 
used before, relieving us of the need think of a name for the lambda parameter.
In particular, this can be used with the above-mentioned String::isBlank and 
String::isEmpty. The main point is that Predicate.not can be used with *any* 
predicate, which lets us avoid adding inverse methods in a bunch of different places.

s'marks



More information about the core-libs-dev mailing list