'Find' method for Iterable

Stuart Marks stuart.marks at oracle.com
Wed Sep 16 22:31:56 UTC 2020



On 9/16/20 1:59 PM, Remi Forax wrote:
> ----- Mail original -----
>> De: "Nir Lisker" <nlisker at gmail.com>
>> À: "core-libs-dev" <core-libs-dev at openjdk.java.net>
>> Envoyé: Lundi 14 Septembre 2020 20:56:27
>> Objet: 'Find' method for Iterable
> 
>> Hi,
>>
>> This has probably been brought up at some point. When we need to find an
>> item in a collection based on its properties, we can either do it in a
>> loop, testing each item, or in a stream with filter and findFirst/Any.
>>
>> I would think that a method in Iterable<T> be useful, along the lines of:
>>
>> public <T> Optional<T> find(Predicate<T> condition) {
>>     Objects.requireNonNull(condition);
>>     for (T t : this) {
>>          if (condition.test(t)) {
>>              return Optional.of(t);
>>         }
>>     }
>>     return Optional.empty();
>> }
>>
>> With usage:
>>
>> list.find(person -> person.id == 123456);
>>
>> There are a few issues with the method here such as t being null in
>> null-friendly collections and the lack of bound generic types, but this
>> example is just used to explain the intention.
>>
>> It will be an alternative to
>>
>> list.stream().filter(person -> person.id == 123456).findAny/First()
>> (depending on if the collection is ordered or not)
>>
>> which doesn't create a stream, similar to Iterable#forEach vs
>> Stream#forEach.
>>
>> Maybe with pattern matching this would become more appetizing.
> 
> During the development of Java 8, we first tried to use Iterator/Iterable instead of using a novel interface Stream.
> But a Stream cleanly separate the lazy side effect free API from the mutable one (Collection) and can be optimized better by the VM (it's a push API instead of being a pull API).
> 
> The other question is why there is no method find() on Collection, i believe it's because while find() is ok for any DB API, find() is dangerous on a Collection because the execution time is linear, so people may use it instead of using a Map.


Hi Nir,

Rémi is correct to point out this distinction between the lazy operations (which 
appear on Stream) and the eager (and possibly mutating) operations on Collections. I 
think we want to preserve this distinction.

While it might not be difficult to add a find() method to Iterable, why limit it to 
the find operation, and what about all the other operations available on Stream? 
Maybe what's necessary is a way to convert an Iterable to a Stream. In fact, this is 
already possible:

     StreamSupport.stream(iterable.spliterator(), false)

Well, this is mouthful, so maybe there ought to be an easier way to convert an 
Iterable to a Stream.

On the other hand, your examples use a list. The List interface already has methods 
indexOf/lastIndexOf which search the list for a particular object that's compared 
using equals(). It seems reasonable to consider similar methods that take a 
predicate instead of an object.

Does either of these sound promising?

s'marks


More information about the core-libs-dev mailing list