• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you
5  * may not use this file except in compliance with the License.  You may
6  * obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13  * implied.  See the License for the specific language governing
14  * permissions and limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.base.Preconditions.checkState;
21 
22 import com.google.common.annotations.Beta;
23 import com.google.common.annotations.GwtCompatible;
24 import com.google.common.math.LongMath;
25 import java.util.ArrayDeque;
26 import java.util.Collection;
27 import java.util.Deque;
28 import java.util.Iterator;
29 import java.util.OptionalDouble;
30 import java.util.OptionalInt;
31 import java.util.OptionalLong;
32 import java.util.PrimitiveIterator;
33 import java.util.Spliterator;
34 import java.util.Spliterators;
35 import java.util.Spliterators.AbstractSpliterator;
36 import java.util.function.BiConsumer;
37 import java.util.function.BiFunction;
38 import java.util.function.Consumer;
39 import java.util.function.DoubleConsumer;
40 import java.util.function.IntConsumer;
41 import java.util.function.LongConsumer;
42 import java.util.stream.DoubleStream;
43 import java.util.stream.IntStream;
44 import java.util.stream.LongStream;
45 import java.util.stream.Stream;
46 import java.util.stream.StreamSupport;
47 import org.checkerframework.checker.nullness.qual.Nullable;
48 
49 /**
50  * Static utility methods related to {@code Stream} instances.
51  *
52  * @since 21.0
53  */
54 @GwtCompatible
55 public final class Streams {
56   /**
57    * Returns a sequential {@link Stream} of the contents of {@code iterable}, delegating to {@link
58    * Collection#stream} if possible.
59    */
stream(Iterable<T> iterable)60   public static <T> Stream<T> stream(Iterable<T> iterable) {
61     return (iterable instanceof Collection)
62         ? ((Collection<T>) iterable).stream()
63         : StreamSupport.stream(iterable.spliterator(), false);
64   }
65 
66   /**
67    * Returns {@link Collection#stream}.
68    *
69    * @deprecated There is no reason to use this; just invoke {@code collection.stream()} directly.
70    */
71   @Beta
72   @Deprecated
stream(Collection<T> collection)73   public static <T> Stream<T> stream(Collection<T> collection) {
74     return collection.stream();
75   }
76 
77   /**
78    * Returns a sequential {@link Stream} of the remaining contents of {@code iterator}. Do not use
79    * {@code iterator} directly after passing it to this method.
80    */
81   @Beta
stream(Iterator<T> iterator)82   public static <T> Stream<T> stream(Iterator<T> iterator) {
83     return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
84   }
85 
86   /**
87    * If a value is present in {@code optional}, returns a stream containing only that element,
88    * otherwise returns an empty stream.
89    */
90   @Beta
stream(com.google.common.base.Optional<T> optional)91   public static <T> Stream<T> stream(com.google.common.base.Optional<T> optional) {
92     return optional.isPresent() ? Stream.of(optional.get()) : Stream.of();
93   }
94 
95   /**
96    * If a value is present in {@code optional}, returns a stream containing only that element,
97    * otherwise returns an empty stream.
98    *
99    * <p><b>Java 9 users:</b> use {@code optional.stream()} instead.
100    */
101   @Beta
stream(java.util.Optional<T> optional)102   public static <T> Stream<T> stream(java.util.Optional<T> optional) {
103     return optional.isPresent() ? Stream.of(optional.get()) : Stream.of();
104   }
105 
106   /**
107    * If a value is present in {@code optional}, returns a stream containing only that element,
108    * otherwise returns an empty stream.
109    *
110    * <p><b>Java 9 users:</b> use {@code optional.stream()} instead.
111    */
112   @Beta
stream(OptionalInt optional)113   public static IntStream stream(OptionalInt optional) {
114     return optional.isPresent() ? IntStream.of(optional.getAsInt()) : IntStream.empty();
115   }
116 
117   /**
118    * If a value is present in {@code optional}, returns a stream containing only that element,
119    * otherwise returns an empty stream.
120    *
121    * <p><b>Java 9 users:</b> use {@code optional.stream()} instead.
122    */
123   @Beta
stream(OptionalLong optional)124   public static LongStream stream(OptionalLong optional) {
125     return optional.isPresent() ? LongStream.of(optional.getAsLong()) : LongStream.empty();
126   }
127 
128   /**
129    * If a value is present in {@code optional}, returns a stream containing only that element,
130    * otherwise returns an empty stream.
131    *
132    * <p><b>Java 9 users:</b> use {@code optional.stream()} instead.
133    */
134   @Beta
stream(OptionalDouble optional)135   public static DoubleStream stream(OptionalDouble optional) {
136     return optional.isPresent() ? DoubleStream.of(optional.getAsDouble()) : DoubleStream.empty();
137   }
138 
139   /**
140    * Returns a {@link Stream} containing the elements of the first stream, followed by the elements
141    * of the second stream, and so on.
142    *
143    * <p>This is equivalent to {@code Stream.of(streams).flatMap(stream -> stream)}, but the returned
144    * stream may perform better.
145    *
146    * @see Stream#concat(Stream, Stream)
147    */
148   @SafeVarargs
concat(Stream<? extends T>.... streams)149   public static <T> Stream<T> concat(Stream<? extends T>... streams) {
150     // TODO(lowasser): consider an implementation that can support SUBSIZED
151     boolean isParallel = false;
152     int characteristics = Spliterator.ORDERED | Spliterator.SIZED | Spliterator.NONNULL;
153     long estimatedSize = 0L;
154     ImmutableList.Builder<Spliterator<? extends T>> splitrsBuilder =
155         new ImmutableList.Builder<>(streams.length);
156     for (Stream<? extends T> stream : streams) {
157       isParallel |= stream.isParallel();
158       Spliterator<? extends T> splitr = stream.spliterator();
159       splitrsBuilder.add(splitr);
160       characteristics &= splitr.characteristics();
161       estimatedSize = LongMath.saturatedAdd(estimatedSize, splitr.estimateSize());
162     }
163     return StreamSupport.stream(
164             CollectSpliterators.flatMap(
165                 splitrsBuilder.build().spliterator(),
166                 splitr -> (Spliterator<T>) splitr,
167                 characteristics,
168                 estimatedSize),
169             isParallel)
170         .onClose(
171             () -> {
172               for (Stream<? extends T> stream : streams) {
173                 stream.close();
174               }
175             });
176   }
177 
178   /**
179    * Returns an {@link IntStream} containing the elements of the first stream, followed by the
180    * elements of the second stream, and so on.
181    *
182    * <p>This is equivalent to {@code Stream.of(streams).flatMapToInt(stream -> stream)}, but the
183    * returned stream may perform better.
184    *
185    * @see IntStream#concat(IntStream, IntStream)
186    */
187   public static IntStream concat(IntStream... streams) {
188     // TODO(lowasser): optimize this later
189     return Stream.of(streams).flatMapToInt(stream -> stream);
190   }
191 
192   /**
193    * Returns a {@link LongStream} containing the elements of the first stream, followed by the
194    * elements of the second stream, and so on.
195    *
196    * <p>This is equivalent to {@code Stream.of(streams).flatMapToLong(stream -> stream)}, but the
197    * returned stream may perform better.
198    *
199    * @see LongStream#concat(LongStream, LongStream)
200    */
201   public static LongStream concat(LongStream... streams) {
202     // TODO(lowasser): optimize this later
203     return Stream.of(streams).flatMapToLong(stream -> stream);
204   }
205 
206   /**
207    * Returns a {@link DoubleStream} containing the elements of the first stream, followed by the
208    * elements of the second stream, and so on.
209    *
210    * <p>This is equivalent to {@code Stream.of(streams).flatMapToDouble(stream -> stream)}, but the
211    * returned stream may perform better.
212    *
213    * @see DoubleStream#concat(DoubleStream, DoubleStream)
214    */
215   public static DoubleStream concat(DoubleStream... streams) {
216     // TODO(lowasser): optimize this later
217     return Stream.of(streams).flatMapToDouble(stream -> stream);
218   }
219 
220   /**
221    * Returns a stream in which each element is the result of passing the corresponding elementY of
222    * each of {@code streamA} and {@code streamB} to {@code function}.
223    *
224    * <p>For example:
225    *
226    * <pre>{@code
227    * Streams.zip(
228    *   Stream.of("foo1", "foo2", "foo3"),
229    *   Stream.of("bar1", "bar2"),
230    *   (arg1, arg2) -> arg1 + ":" + arg2)
231    * }</pre>
232    *
233    * <p>will return {@code Stream.of("foo1:bar1", "foo2:bar2")}.
234    *
235    * <p>The resulting stream will only be as long as the shorter of the two input streams; if one
236    * stream is longer, its extra elements will be ignored.
237    *
238    * <p>Note that if you are calling {@link Stream#forEach} on the resulting stream, you might want
239    * to consider using {@link #forEachPair} instead of this method.
240    *
241    * <p><b>Performance note:</b> The resulting stream is not <a
242    * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>.
243    * This may harm parallel performance.
244    */
245   @Beta
246   public static <A, B, R> Stream<R> zip(
247       Stream<A> streamA, Stream<B> streamB, BiFunction<? super A, ? super B, R> function) {
248     checkNotNull(streamA);
249     checkNotNull(streamB);
250     checkNotNull(function);
251     boolean isParallel = streamA.isParallel() || streamB.isParallel(); // same as Stream.concat
252     Spliterator<A> splitrA = streamA.spliterator();
253     Spliterator<B> splitrB = streamB.spliterator();
254     int characteristics =
255         splitrA.characteristics()
256             & splitrB.characteristics()
257             & (Spliterator.SIZED | Spliterator.ORDERED);
258     Iterator<A> itrA = Spliterators.iterator(splitrA);
259     Iterator<B> itrB = Spliterators.iterator(splitrB);
260     return StreamSupport.stream(
261             new AbstractSpliterator<R>(
262                 Math.min(splitrA.estimateSize(), splitrB.estimateSize()), characteristics) {
263               @Override
264               public boolean tryAdvance(Consumer<? super R> action) {
265                 if (itrA.hasNext() && itrB.hasNext()) {
266                   action.accept(function.apply(itrA.next(), itrB.next()));
267                   return true;
268                 }
269                 return false;
270               }
271             },
272             isParallel)
273         .onClose(streamA::close)
274         .onClose(streamB::close);
275   }
276 
277   /**
278    * Invokes {@code consumer} once for each pair of <i>corresponding</i> elements in {@code streamA}
279    * and {@code streamB}. If one stream is longer than the other, the extra elements are silently
280    * ignored. Elements passed to the consumer are guaranteed to come from the same position in their
281    * respective source streams. For example:
282    *
283    * <pre>{@code
284    * Streams.forEachPair(
285    *   Stream.of("foo1", "foo2", "foo3"),
286    *   Stream.of("bar1", "bar2"),
287    *   (arg1, arg2) -> System.out.println(arg1 + ":" + arg2)
288    * }</pre>
289    *
290    * <p>will print:
291    *
292    * <pre>{@code
293    * foo1:bar1
294    * foo2:bar2
295    * }</pre>
296    *
297    * <p><b>Warning:</b> If either supplied stream is a parallel stream, the same correspondence
298    * between elements will be made, but the order in which those pairs of elements are passed to the
299    * consumer is <i>not</i> defined.
300    *
301    * <p>Note that many usages of this method can be replaced with simpler calls to {@link #zip}.
302    * This method behaves equivalently to {@linkplain #zip zipping} the stream elements into
303    * temporary pair objects and then using {@link Stream#forEach} on that stream.
304    *
305    * @since 22.0
306    */
307   @Beta
308   public static <A, B> void forEachPair(
309       Stream<A> streamA, Stream<B> streamB, BiConsumer<? super A, ? super B> consumer) {
310     checkNotNull(consumer);
311 
312     if (streamA.isParallel() || streamB.isParallel()) {
313       zip(streamA, streamB, TemporaryPair::new).forEach(pair -> consumer.accept(pair.a, pair.b));
314     } else {
315       Iterator<A> iterA = streamA.iterator();
316       Iterator<B> iterB = streamB.iterator();
317       while (iterA.hasNext() && iterB.hasNext()) {
318         consumer.accept(iterA.next(), iterB.next());
319       }
320     }
321   }
322 
323   // Use this carefully - it doesn't implement value semantics
324   private static class TemporaryPair<A, B> {
325     final A a;
326     final B b;
327 
328     TemporaryPair(A a, B b) {
329       this.a = a;
330       this.b = b;
331     }
332   }
333 
334   /**
335    * Returns a stream consisting of the results of applying the given function to the elements of
336    * {@code stream} and their indices in the stream. For example,
337    *
338    * <pre>{@code
339    * mapWithIndex(
340    *     Stream.of("a", "b", "c"),
341    *     (str, index) -> str + ":" + index)
342    * }</pre>
343    *
344    * <p>would return {@code Stream.of("a:0", "b:1", "c:2")}.
345    *
346    * <p>The resulting stream is <a
347    * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
348    * if and only if {@code stream} was efficiently splittable and its underlying spliterator
349    * reported {@link Spliterator#SUBSIZED}. This is generally the case if the underlying stream
350    * comes from a data structure supporting efficient indexed random access, typically an array or
351    * list.
352    *
353    * <p>The order of the resulting stream is defined if and only if the order of the original stream
354    * was defined.
355    */
356   @Beta
357   public static <T, R> Stream<R> mapWithIndex(
358       Stream<T> stream, FunctionWithIndex<? super T, ? extends R> function) {
359     checkNotNull(stream);
360     checkNotNull(function);
361     boolean isParallel = stream.isParallel();
362     Spliterator<T> fromSpliterator = stream.spliterator();
363 
364     if (!fromSpliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
365       Iterator<T> fromIterator = Spliterators.iterator(fromSpliterator);
366       return StreamSupport.stream(
367               new AbstractSpliterator<R>(
368                   fromSpliterator.estimateSize(),
369                   fromSpliterator.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
370                 long index = 0;
371 
372                 @Override
373                 public boolean tryAdvance(Consumer<? super R> action) {
374                   if (fromIterator.hasNext()) {
375                     action.accept(function.apply(fromIterator.next(), index++));
376                     return true;
377                   }
378                   return false;
379                 }
380               },
381               isParallel)
382           .onClose(stream::close);
383     }
384     class Splitr extends MapWithIndexSpliterator<Spliterator<T>, R, Splitr> implements Consumer<T> {
385       @Nullable T holder;
386 
387       Splitr(Spliterator<T> splitr, long index) {
388         super(splitr, index);
389       }
390 
391       @Override
392       public void accept(@Nullable T t) {
393         this.holder = t;
394       }
395 
396       @Override
397       public boolean tryAdvance(Consumer<? super R> action) {
398         if (fromSpliterator.tryAdvance(this)) {
399           try {
400             action.accept(function.apply(holder, index++));
401             return true;
402           } finally {
403             holder = null;
404           }
405         }
406         return false;
407       }
408 
409       @Override
410       Splitr createSplit(Spliterator<T> from, long i) {
411         return new Splitr(from, i);
412       }
413     }
414     return StreamSupport.stream(new Splitr(fromSpliterator, 0), isParallel).onClose(stream::close);
415   }
416 
417   /**
418    * Returns a stream consisting of the results of applying the given function to the elements of
419    * {@code stream} and their indexes in the stream. For example,
420    *
421    * <pre>{@code
422    * mapWithIndex(
423    *     IntStream.of(0, 1, 2),
424    *     (i, index) -> i + ":" + index)
425    * }</pre>
426    *
427    * <p>...would return {@code Stream.of("0:0", "1:1", "2:2")}.
428    *
429    * <p>The resulting stream is <a
430    * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
431    * if and only if {@code stream} was efficiently splittable and its underlying spliterator
432    * reported {@link Spliterator#SUBSIZED}. This is generally the case if the underlying stream
433    * comes from a data structure supporting efficient indexed random access, typically an array or
434    * list.
435    *
436    * <p>The order of the resulting stream is defined if and only if the order of the original stream
437    * was defined.
438    */
439   @Beta
440   public static <R> Stream<R> mapWithIndex(IntStream stream, IntFunctionWithIndex<R> function) {
441     checkNotNull(stream);
442     checkNotNull(function);
443     boolean isParallel = stream.isParallel();
444     Spliterator.OfInt fromSpliterator = stream.spliterator();
445 
446     if (!fromSpliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
447       PrimitiveIterator.OfInt fromIterator = Spliterators.iterator(fromSpliterator);
448       return StreamSupport.stream(
449               new AbstractSpliterator<R>(
450                   fromSpliterator.estimateSize(),
451                   fromSpliterator.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
452                 long index = 0;
453 
454                 @Override
455                 public boolean tryAdvance(Consumer<? super R> action) {
456                   if (fromIterator.hasNext()) {
457                     action.accept(function.apply(fromIterator.nextInt(), index++));
458                     return true;
459                   }
460                   return false;
461                 }
462               },
463               isParallel)
464           .onClose(stream::close);
465     }
466     class Splitr extends MapWithIndexSpliterator<Spliterator.OfInt, R, Splitr>
467         implements IntConsumer, Spliterator<R> {
468       int holder;
469 
470       Splitr(Spliterator.OfInt splitr, long index) {
471         super(splitr, index);
472       }
473 
474       @Override
475       public void accept(int t) {
476         this.holder = t;
477       }
478 
479       @Override
480       public boolean tryAdvance(Consumer<? super R> action) {
481         if (fromSpliterator.tryAdvance(this)) {
482           action.accept(function.apply(holder, index++));
483           return true;
484         }
485         return false;
486       }
487 
488       @Override
489       Splitr createSplit(Spliterator.OfInt from, long i) {
490         return new Splitr(from, i);
491       }
492     }
493     return StreamSupport.stream(new Splitr(fromSpliterator, 0), isParallel).onClose(stream::close);
494   }
495 
496   /**
497    * Returns a stream consisting of the results of applying the given function to the elements of
498    * {@code stream} and their indexes in the stream. For example,
499    *
500    * <pre>{@code
501    * mapWithIndex(
502    *     LongStream.of(0, 1, 2),
503    *     (i, index) -> i + ":" + index)
504    * }</pre>
505    *
506    * <p>...would return {@code Stream.of("0:0", "1:1", "2:2")}.
507    *
508    * <p>The resulting stream is <a
509    * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
510    * if and only if {@code stream} was efficiently splittable and its underlying spliterator
511    * reported {@link Spliterator#SUBSIZED}. This is generally the case if the underlying stream
512    * comes from a data structure supporting efficient indexed random access, typically an array or
513    * list.
514    *
515    * <p>The order of the resulting stream is defined if and only if the order of the original stream
516    * was defined.
517    */
518   @Beta
519   public static <R> Stream<R> mapWithIndex(LongStream stream, LongFunctionWithIndex<R> function) {
520     checkNotNull(stream);
521     checkNotNull(function);
522     boolean isParallel = stream.isParallel();
523     Spliterator.OfLong fromSpliterator = stream.spliterator();
524 
525     if (!fromSpliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
526       PrimitiveIterator.OfLong fromIterator = Spliterators.iterator(fromSpliterator);
527       return StreamSupport.stream(
528               new AbstractSpliterator<R>(
529                   fromSpliterator.estimateSize(),
530                   fromSpliterator.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
531                 long index = 0;
532 
533                 @Override
534                 public boolean tryAdvance(Consumer<? super R> action) {
535                   if (fromIterator.hasNext()) {
536                     action.accept(function.apply(fromIterator.nextLong(), index++));
537                     return true;
538                   }
539                   return false;
540                 }
541               },
542               isParallel)
543           .onClose(stream::close);
544     }
545     class Splitr extends MapWithIndexSpliterator<Spliterator.OfLong, R, Splitr>
546         implements LongConsumer, Spliterator<R> {
547       long holder;
548 
549       Splitr(Spliterator.OfLong splitr, long index) {
550         super(splitr, index);
551       }
552 
553       @Override
554       public void accept(long t) {
555         this.holder = t;
556       }
557 
558       @Override
559       public boolean tryAdvance(Consumer<? super R> action) {
560         if (fromSpliterator.tryAdvance(this)) {
561           action.accept(function.apply(holder, index++));
562           return true;
563         }
564         return false;
565       }
566 
567       @Override
568       Splitr createSplit(Spliterator.OfLong from, long i) {
569         return new Splitr(from, i);
570       }
571     }
572     return StreamSupport.stream(new Splitr(fromSpliterator, 0), isParallel).onClose(stream::close);
573   }
574 
575   /**
576    * Returns a stream consisting of the results of applying the given function to the elements of
577    * {@code stream} and their indexes in the stream. For example,
578    *
579    * <pre>{@code
580    * mapWithIndex(
581    *     DoubleStream.of(0, 1, 2),
582    *     (x, index) -> x + ":" + index)
583    * }</pre>
584    *
585    * <p>...would return {@code Stream.of("0.0:0", "1.0:1", "2.0:2")}.
586    *
587    * <p>The resulting stream is <a
588    * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
589    * if and only if {@code stream} was efficiently splittable and its underlying spliterator
590    * reported {@link Spliterator#SUBSIZED}. This is generally the case if the underlying stream
591    * comes from a data structure supporting efficient indexed random access, typically an array or
592    * list.
593    *
594    * <p>The order of the resulting stream is defined if and only if the order of the original stream
595    * was defined.
596    */
597   @Beta
598   public static <R> Stream<R> mapWithIndex(
599       DoubleStream stream, DoubleFunctionWithIndex<R> function) {
600     checkNotNull(stream);
601     checkNotNull(function);
602     boolean isParallel = stream.isParallel();
603     Spliterator.OfDouble fromSpliterator = stream.spliterator();
604 
605     if (!fromSpliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
606       PrimitiveIterator.OfDouble fromIterator = Spliterators.iterator(fromSpliterator);
607       return StreamSupport.stream(
608               new AbstractSpliterator<R>(
609                   fromSpliterator.estimateSize(),
610                   fromSpliterator.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
611                 long index = 0;
612 
613                 @Override
614                 public boolean tryAdvance(Consumer<? super R> action) {
615                   if (fromIterator.hasNext()) {
616                     action.accept(function.apply(fromIterator.nextDouble(), index++));
617                     return true;
618                   }
619                   return false;
620                 }
621               },
622               isParallel)
623           .onClose(stream::close);
624     }
625     class Splitr extends MapWithIndexSpliterator<Spliterator.OfDouble, R, Splitr>
626         implements DoubleConsumer, Spliterator<R> {
627       double holder;
628 
629       Splitr(Spliterator.OfDouble splitr, long index) {
630         super(splitr, index);
631       }
632 
633       @Override
634       public void accept(double t) {
635         this.holder = t;
636       }
637 
638       @Override
639       public boolean tryAdvance(Consumer<? super R> action) {
640         if (fromSpliterator.tryAdvance(this)) {
641           action.accept(function.apply(holder, index++));
642           return true;
643         }
644         return false;
645       }
646 
647       @Override
648       Splitr createSplit(Spliterator.OfDouble from, long i) {
649         return new Splitr(from, i);
650       }
651     }
652     return StreamSupport.stream(new Splitr(fromSpliterator, 0), isParallel).onClose(stream::close);
653   }
654 
655   /**
656    * An analogue of {@link java.util.function.Function} also accepting an index.
657    *
658    * <p>This interface is only intended for use by callers of {@link #mapWithIndex(Stream,
659    * FunctionWithIndex)}.
660    *
661    * @since 21.0
662    */
663   @Beta
664   public interface FunctionWithIndex<T, R> {
665     /** Applies this function to the given argument and its index within a stream. */
666     R apply(T from, long index);
667   }
668 
669   private abstract static class MapWithIndexSpliterator<
670           F extends Spliterator<?>, R, S extends MapWithIndexSpliterator<F, R, S>>
671       implements Spliterator<R> {
672     final F fromSpliterator;
673     long index;
674 
675     MapWithIndexSpliterator(F fromSpliterator, long index) {
676       this.fromSpliterator = fromSpliterator;
677       this.index = index;
678     }
679 
680     abstract S createSplit(F from, long i);
681 
682     @Override
683     public S trySplit() {
684       @SuppressWarnings("unchecked")
685       F split = (F) fromSpliterator.trySplit();
686       if (split == null) {
687         return null;
688       }
689       S result = createSplit(split, index);
690       this.index += split.getExactSizeIfKnown();
691       return result;
692     }
693 
694     @Override
695     public long estimateSize() {
696       return fromSpliterator.estimateSize();
697     }
698 
699     @Override
700     public int characteristics() {
701       return fromSpliterator.characteristics()
702           & (Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED);
703     }
704   }
705 
706   /**
707    * An analogue of {@link java.util.function.IntFunction} also accepting an index.
708    *
709    * <p>This interface is only intended for use by callers of {@link #mapWithIndex(IntStream,
710    * IntFunctionWithIndex)}.
711    *
712    * @since 21.0
713    */
714   @Beta
715   public interface IntFunctionWithIndex<R> {
716     /** Applies this function to the given argument and its index within a stream. */
717     R apply(int from, long index);
718   }
719 
720   /**
721    * An analogue of {@link java.util.function.LongFunction} also accepting an index.
722    *
723    * <p>This interface is only intended for use by callers of {@link #mapWithIndex(LongStream,
724    * LongFunctionWithIndex)}.
725    *
726    * @since 21.0
727    */
728   @Beta
729   public interface LongFunctionWithIndex<R> {
730     /** Applies this function to the given argument and its index within a stream. */
731     R apply(long from, long index);
732   }
733 
734   /**
735    * An analogue of {@link java.util.function.DoubleFunction} also accepting an index.
736    *
737    * <p>This interface is only intended for use by callers of {@link #mapWithIndex(DoubleStream,
738    * DoubleFunctionWithIndex)}.
739    *
740    * @since 21.0
741    */
742   @Beta
743   public interface DoubleFunctionWithIndex<R> {
744     /** Applies this function to the given argument and its index within a stream. */
745     R apply(double from, long index);
746   }
747 
748   /**
749    * Returns the last element of the specified stream, or {@link java.util.Optional#empty} if the
750    * stream is empty.
751    *
752    * <p>Equivalent to {@code stream.reduce((a, b) -> b)}, but may perform significantly better. This
753    * method's runtime will be between O(log n) and O(n), performing better on <a
754    * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
755    * streams.
756    *
757    * <p>If the stream has nondeterministic order, this has equivalent semantics to {@link
758    * Stream#findAny} (which you might as well use).
759    *
760    * @see Stream#findFirst()
761    * @throws NullPointerException if the last element of the stream is null
762    */
763   @Beta
764   public static <T> java.util.Optional<T> findLast(Stream<T> stream) {
765     class OptionalState {
766       boolean set = false;
767       T value = null;
768 
769       void set(@Nullable T value) {
770         this.set = true;
771         this.value = value;
772       }
773 
774       T get() {
775         checkState(set);
776         return value;
777       }
778     }
779     OptionalState state = new OptionalState();
780 
781     Deque<Spliterator<T>> splits = new ArrayDeque<>();
782     splits.addLast(stream.spliterator());
783 
784     while (!splits.isEmpty()) {
785       Spliterator<T> spliterator = splits.removeLast();
786 
787       if (spliterator.getExactSizeIfKnown() == 0) {
788         continue; // drop this split
789       }
790 
791       // Many spliterators will have trySplits that are SUBSIZED even if they are not themselves
792       // SUBSIZED.
793       if (spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
794         // we can drill down to exactly the smallest nonempty spliterator
795         while (true) {
796           Spliterator<T> prefix = spliterator.trySplit();
797           if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
798             break;
799           } else if (spliterator.getExactSizeIfKnown() == 0) {
800             spliterator = prefix;
801             break;
802           }
803         }
804 
805         // spliterator is known to be nonempty now
806         spliterator.forEachRemaining(state::set);
807         return java.util.Optional.of(state.get());
808       }
809 
810       Spliterator<T> prefix = spliterator.trySplit();
811       if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
812         // we can't split this any further
813         spliterator.forEachRemaining(state::set);
814         if (state.set) {
815           return java.util.Optional.of(state.get());
816         }
817         // fall back to the last split
818         continue;
819       }
820       splits.addLast(prefix);
821       splits.addLast(spliterator);
822     }
823     return java.util.Optional.empty();
824   }
825 
826   /**
827    * Returns the last element of the specified stream, or {@link OptionalInt#empty} if the stream is
828    * empty.
829    *
830    * <p>Equivalent to {@code stream.reduce((a, b) -> b)}, but may perform significantly better. This
831    * method's runtime will be between O(log n) and O(n), performing better on <a
832    * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
833    * streams.
834    *
835    * @see IntStream#findFirst()
836    * @throws NullPointerException if the last element of the stream is null
837    */
838   @Beta
839   public static OptionalInt findLast(IntStream stream) {
840     // findLast(Stream) does some allocation, so we might as well box some more
841     java.util.Optional<Integer> boxedLast = findLast(stream.boxed());
842     return boxedLast.isPresent() ? OptionalInt.of(boxedLast.get()) : OptionalInt.empty();
843   }
844 
845   /**
846    * Returns the last element of the specified stream, or {@link OptionalLong#empty} if the stream
847    * is empty.
848    *
849    * <p>Equivalent to {@code stream.reduce((a, b) -> b)}, but may perform significantly better. This
850    * method's runtime will be between O(log n) and O(n), performing better on <a
851    * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
852    * streams.
853    *
854    * @see LongStream#findFirst()
855    * @throws NullPointerException if the last element of the stream is null
856    */
857   @Beta
858   public static OptionalLong findLast(LongStream stream) {
859     // findLast(Stream) does some allocation, so we might as well box some more
860     java.util.Optional<Long> boxedLast = findLast(stream.boxed());
861     return boxedLast.isPresent() ? OptionalLong.of(boxedLast.get()) : OptionalLong.empty();
862   }
863 
864   /**
865    * Returns the last element of the specified stream, or {@link OptionalDouble#empty} if the stream
866    * is empty.
867    *
868    * <p>Equivalent to {@code stream.reduce((a, b) -> b)}, but may perform significantly better. This
869    * method's runtime will be between O(log n) and O(n), performing better on <a
870    * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
871    * streams.
872    *
873    * @see DoubleStream#findFirst()
874    * @throws NullPointerException if the last element of the stream is null
875    */
876   @Beta
877   public static OptionalDouble findLast(DoubleStream stream) {
878     // findLast(Stream) does some allocation, so we might as well box some more
879     java.util.Optional<Double> boxedLast = findLast(stream.boxed());
880     return boxedLast.isPresent() ? OptionalDouble.of(boxedLast.get()) : OptionalDouble.empty();
881   }
882 
883   private Streams() {}
884 }
885