Finding the First or Any Element – Streams
By Stephen Trude / July 23, 2022 / No Comments / Certifications of Oracle, Collecting to an Array, Consumer Action on Stream Elements, Creating an Optional, Multilevel Partitioning, Numeric Optional Classes
Finding the First or Any Element
The findFirst() method can be used to find the first element that is available in the stream. This method respects the encounter order, if the stream has one. It always produces a stable result; that is, it will produce the same result on identical pipelines based on the same stream source. In contrast, the behavior of the findAny() method is nondeterministic. Counterparts to these methods are also defined by the numeric stream interfaces.
Optional<T> findFirst()
This terminal operation returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty.
This method may return any element if this stream does not have any encounter order.
It is a short-circuit operation, as it will terminate the execution of the stream pipeline as soon as the first element is found.
This method throws a NullPointerException if the element selected is null.
Optional<T> findAny()
This terminal operation returns an Optional describing some element of the stream, or an empty Optional if the stream is empty. This operation has nondeterministic behavior.
It is a short-circuit operation, as it will terminate the execution of the stream pipeline as soon as any element is found.
In the code below, the encounter order of the stream is the positional order of the elements in the list. The first element returned by the findFirst() method at (1) is the first element in the CD list.
Optional<CD> firstCD1 = CD.cdList.stream().findFirst(); // (1)
out.println(firstCD1.map(CD::title).orElse(“No first CD.”)); // (2) Java Jive
Since such an element might not exist—for example, the stream might be empty— the method returns an Optional<T> object. At (2), the Optional<CD> object returned by the findFirst() method is mapped to an Optional<String> object that encapsulates the title of the CD. The orElse() method on this Optional<String> object returns the CD title or the argument string if there is no such CD.
If the encounter order is not of consequence, the findAny() method can be used, as it is nondeterministic—that is, it does not guarantee the same result on the same stream source. On the other hand, it provides maximal performance on parallel streams. At (3) below, the findAny() method is free to return any element from the parallel stream. It should not come as a surprise if the element returned is not the first element in the list.
Optional<CD> anyCD2 = CD.cdList.stream().parallel().findAny(); // (3)
out.println(anyCD2.map(CD::title).orElse(“No CD.”)); // Lambda Dancing
The match methods only determine whether any elements satisfy a Predicate, as seen at (5) below. Typically, a find terminal operation is used to find the first element made available to the terminal operation after processing by the intermediate operations in the stream pipeline. At (6), the filter() operation will filter the jazz music CDs from the stream. However, the findAny() operation will return the first jazz music CD that is filtered and then short-circuit the execution.
boolean anyJazzCD = CD.cdList.stream().anyMatch(CD::isJazz); // (5)
out.println(“Any Jazz CD: ” + anyJazzCD); // Any Jazz CD: true
Optional<CD> optJazzCD = CD.cdList.stream().filter(CD::isJazz).findAny(); // (6)
optJazzCD.ifPresent(out::println); // <Jaav, “Java Jam”, 6, 2017, JAZZ>
The code below uses the findAny() method on an IntStream to find whether any number is divisible by 7.
IntStream numStream = IntStream.of(50, 55, 65, 70, 75, 77);
OptionalInt intOpt = numStream.filter(n -> n % 7 == 0).findAny();
intOpt.ifPresent(System.out::println); // 70
The find operations are guaranteed to terminate when applied to a finite, albeit empty, stream. However, for an infinite stream in a pipeline, at least one element must be made available to the find operation in order for the operation to terminate. If the elements of an initial infinite stream are all discarded by the intermediate operations, the find operation will not terminate, as in the following pipeline:
Click here to view code image Stream.generate(() -> 1).filter(n -> n == 0).findAny(); // Never terminates.