On Sat, 6 Nov 2021 22:03:26 GMT, Pavel Rappo <[email protected]> wrote:
>> This is a draft proposal for how we could improve stream performance for the
>> case where the streams are empty. Empty collections are common-place. If we
>> iterate over them with an Iterator, we would have to create one small
>> Iterator object (which could often be eliminated) and if it is empty we are
>> done. However, with Streams we first have to build up the entire pipeline,
>> until we realize that there is no work to do. With this example, we change
>> Collection#stream() to first check if the collection is empty, and if it is,
>> we simply return an EmptyStream. We also have EmptyIntStream,
>> EmptyLongStream and EmptyDoubleStream. We have taken great care for these to
>> have the same characteristics and behaviour as the streams returned by
>> Stream.empty(), IntStream.empty(), etc.
>>
>> Some of the JDK tests fail with this, due to ClassCastExceptions (our
>> EmptyStream is not an AbstractPipeline) and AssertionError, since we can
>> call some methods repeatedly on the stream without it failing. On the plus
>> side, creating a complex stream on an empty stream gives us upwards of 50x
>> increase in performance due to a much smaller object allocation rate. This
>> PR includes the code for the change, unit tests and also a JMH benchmark to
>> demonstrate the improvement.
>
> src/java.base/share/classes/java/util/Collection.java line 743:
>
>> 741: */
>> 742: default Stream<E> stream() {
>> 743: if (isEmpty()) return Stream.empty();
>
> The net effect of this change might depend on your workload. If you call
> stream() on empty collections that have cheap isEmpty(), this change will
> likely improve performance and reduce waste. However, this same change might
> do the opposite if some of your collections aren't empty or have costly
> isEmpty(). It would be good to have benchmarks for different workloads.
wouldn't this make streams no longer lazy if the collection is empty?
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
list.addAll(List.of("one", "two", "three"));
stream.forEach(System.out::println); // prints one two three
-------------
PR: https://git.openjdk.java.net/jdk/pull/6275