• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.util.stream;
26 
27 import java.util.Comparator;
28 import java.util.Objects;
29 import java.util.Spliterator;
30 import java.util.function.Consumer;
31 import java.util.function.DoubleConsumer;
32 import java.util.function.IntConsumer;
33 import java.util.function.LongConsumer;
34 
35 /**
36  * Utility methods for operating on and creating streams.
37  *
38  * <p>Unless otherwise stated, streams are created as sequential streams.  A
39  * sequential stream can be transformed into a parallel stream by calling the
40  * {@code parallel()} method on the created stream.
41  *
42  * @since 1.8
43  */
44 final class Streams {
45 
Streams()46     private Streams() {
47         throw new Error("no instances");
48     }
49 
50     /**
51      * An object instance representing no value, that cannot be an actual
52      * data element of a stream.  Used when processing streams that can contain
53      * {@code null} elements to distinguish between a {@code null} value and no
54      * value.
55      */
56     static final Object NONE = new Object();
57 
58     /**
59      * An {@code int} range spliterator.
60      */
61     static final class RangeIntSpliterator implements Spliterator.OfInt {
62         // Can never be greater that upTo, this avoids overflow if upper bound
63         // is Integer.MAX_VALUE
64         // All elements are traversed if from == upTo & last == 0
65         private int from;
66         private final int upTo;
67         // 1 if the range is closed and the last element has not been traversed
68         // Otherwise, 0 if the range is open, or is a closed range and all
69         // elements have been traversed
70         private int last;
71 
RangeIntSpliterator(int from, int upTo, boolean closed)72         RangeIntSpliterator(int from, int upTo, boolean closed) {
73             this(from, upTo, closed ? 1 : 0);
74         }
75 
RangeIntSpliterator(int from, int upTo, int last)76         private RangeIntSpliterator(int from, int upTo, int last) {
77             this.from = from;
78             this.upTo = upTo;
79             this.last = last;
80         }
81 
82         @Override
tryAdvance(IntConsumer consumer)83         public boolean tryAdvance(IntConsumer consumer) {
84             Objects.requireNonNull(consumer);
85 
86             final int i = from;
87             if (i < upTo) {
88                 from++;
89                 consumer.accept(i);
90                 return true;
91             }
92             else if (last > 0) {
93                 last = 0;
94                 consumer.accept(i);
95                 return true;
96             }
97             return false;
98         }
99 
100         @Override
forEachRemaining(IntConsumer consumer)101         public void forEachRemaining(IntConsumer consumer) {
102             Objects.requireNonNull(consumer);
103 
104             int i = from;
105             final int hUpTo = upTo;
106             int hLast = last;
107             from = upTo;
108             last = 0;
109             while (i < hUpTo) {
110                 consumer.accept(i++);
111             }
112             if (hLast > 0) {
113                 // Last element of closed range
114                 consumer.accept(i);
115             }
116         }
117 
118         @Override
estimateSize()119         public long estimateSize() {
120             // Ensure ranges of size > Integer.MAX_VALUE report the correct size
121             return ((long) upTo) - from + last;
122         }
123 
124         @Override
characteristics()125         public int characteristics() {
126             return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
127                    Spliterator.IMMUTABLE | Spliterator.NONNULL |
128                    Spliterator.DISTINCT | Spliterator.SORTED;
129         }
130 
131         @Override
getComparator()132         public Comparator<? super Integer> getComparator() {
133             return null;
134         }
135 
136         @Override
trySplit()137         public Spliterator.OfInt trySplit() {
138             long size = estimateSize();
139             return size <= 1
140                    ? null
141                    // Left split always has a half-open range
142                    : new RangeIntSpliterator(from, from = from + splitPoint(size), 0);
143         }
144 
145         /**
146          * The spliterator size below which the spliterator will be split
147          * at the mid-point to produce balanced splits. Above this size the
148          * spliterator will be split at a ratio of
149          * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
150          * to produce right-balanced splits.
151          *
152          * <p>Such splitting ensures that for very large ranges that the left
153          * side of the range will more likely be processed at a lower-depth
154          * than a balanced tree at the expense of a higher-depth for the right
155          * side of the range.
156          *
157          * <p>This is optimized for cases such as IntStream.ints() that is
158          * implemented as range of 0 to Integer.MAX_VALUE but is likely to be
159          * augmented with a limit operation that limits the number of elements
160          * to a count lower than this threshold.
161          */
162         private static final int BALANCED_SPLIT_THRESHOLD = 1 << 24;
163 
164         /**
165          * The split ratio of the left and right split when the spliterator
166          * size is above BALANCED_SPLIT_THRESHOLD.
167          */
168         private static final int RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
169 
splitPoint(long size)170         private int splitPoint(long size) {
171             int d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
172             // Cast to int is safe since:
173             //   2 <= size < 2^32
174             //   2 <= d <= 8
175             return (int) (size / d);
176         }
177     }
178 
179     /**
180      * A {@code long} range spliterator.
181      *
182      * This implementation cannot be used for ranges whose size is greater
183      * than Long.MAX_VALUE
184      */
185     static final class RangeLongSpliterator implements Spliterator.OfLong {
186         // Can never be greater that upTo, this avoids overflow if upper bound
187         // is Long.MAX_VALUE
188         // All elements are traversed if from == upTo & last == 0
189         private long from;
190         private final long upTo;
191         // 1 if the range is closed and the last element has not been traversed
192         // Otherwise, 0 if the range is open, or is a closed range and all
193         // elements have been traversed
194         private int last;
195 
RangeLongSpliterator(long from, long upTo, boolean closed)196         RangeLongSpliterator(long from, long upTo, boolean closed) {
197             this(from, upTo, closed ? 1 : 0);
198         }
199 
RangeLongSpliterator(long from, long upTo, int last)200         private RangeLongSpliterator(long from, long upTo, int last) {
201             assert upTo - from + last > 0;
202             this.from = from;
203             this.upTo = upTo;
204             this.last = last;
205         }
206 
207         @Override
tryAdvance(LongConsumer consumer)208         public boolean tryAdvance(LongConsumer consumer) {
209             Objects.requireNonNull(consumer);
210 
211             final long i = from;
212             if (i < upTo) {
213                 from++;
214                 consumer.accept(i);
215                 return true;
216             }
217             else if (last > 0) {
218                 last = 0;
219                 consumer.accept(i);
220                 return true;
221             }
222             return false;
223         }
224 
225         @Override
forEachRemaining(LongConsumer consumer)226         public void forEachRemaining(LongConsumer consumer) {
227             Objects.requireNonNull(consumer);
228 
229             long i = from;
230             final long hUpTo = upTo;
231             int hLast = last;
232             from = upTo;
233             last = 0;
234             while (i < hUpTo) {
235                 consumer.accept(i++);
236             }
237             if (hLast > 0) {
238                 // Last element of closed range
239                 consumer.accept(i);
240             }
241         }
242 
243         @Override
estimateSize()244         public long estimateSize() {
245             return upTo - from + last;
246         }
247 
248         @Override
characteristics()249         public int characteristics() {
250             return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
251                    Spliterator.IMMUTABLE | Spliterator.NONNULL |
252                    Spliterator.DISTINCT | Spliterator.SORTED;
253         }
254 
255         @Override
getComparator()256         public Comparator<? super Long> getComparator() {
257             return null;
258         }
259 
260         @Override
trySplit()261         public Spliterator.OfLong trySplit() {
262             long size = estimateSize();
263             return size <= 1
264                    ? null
265                    // Left split always has a half-open range
266                    : new RangeLongSpliterator(from, from = from + splitPoint(size), 0);
267         }
268 
269         /**
270          * The spliterator size below which the spliterator will be split
271          * at the mid-point to produce balanced splits. Above this size the
272          * spliterator will be split at a ratio of
273          * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
274          * to produce right-balanced splits.
275          *
276          * <p>Such splitting ensures that for very large ranges that the left
277          * side of the range will more likely be processed at a lower-depth
278          * than a balanced tree at the expense of a higher-depth for the right
279          * side of the range.
280          *
281          * <p>This is optimized for cases such as LongStream.longs() that is
282          * implemented as range of 0 to Long.MAX_VALUE but is likely to be
283          * augmented with a limit operation that limits the number of elements
284          * to a count lower than this threshold.
285          */
286         private static final long BALANCED_SPLIT_THRESHOLD = 1 << 24;
287 
288         /**
289          * The split ratio of the left and right split when the spliterator
290          * size is above BALANCED_SPLIT_THRESHOLD.
291          */
292         private static final long RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
293 
splitPoint(long size)294         private long splitPoint(long size) {
295             long d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
296             // 2 <= size <= Long.MAX_VALUE
297             return size / d;
298         }
299     }
300 
301     private static abstract class AbstractStreamBuilderImpl<T, S extends Spliterator<T>> implements Spliterator<T> {
302         // >= 0 when building, < 0 when built
303         // -1 == no elements
304         // -2 == one element, held by first
305         // -3 == two or more elements, held by buffer
306         int count;
307 
308         // Spliterator implementation for 0 or 1 element
309         // count == -1 for no elements
310         // count == -2 for one element held by first
311 
312         @Override
trySplit()313         public S trySplit() {
314             return null;
315         }
316 
317         @Override
estimateSize()318         public long estimateSize() {
319             return -count - 1;
320         }
321 
322         @Override
characteristics()323         public int characteristics() {
324             return Spliterator.SIZED | Spliterator.SUBSIZED |
325                    Spliterator.ORDERED | Spliterator.IMMUTABLE;
326         }
327     }
328 
329     static final class StreamBuilderImpl<T>
330             extends AbstractStreamBuilderImpl<T, Spliterator<T>>
331             implements Stream.Builder<T> {
332         // The first element in the stream
333         // valid if count == 1
334         T first;
335 
336         // The first and subsequent elements in the stream
337         // non-null if count == 2
338         SpinedBuffer<T> buffer;
339 
340         /**
341          * Constructor for building a stream of 0 or more elements.
342          */
StreamBuilderImpl()343         StreamBuilderImpl() { }
344 
345         /**
346          * Constructor for a singleton stream.
347          *
348          * @param t the single element
349          */
StreamBuilderImpl(T t)350         StreamBuilderImpl(T t) {
351             first = t;
352             count = -2;
353         }
354 
355         // StreamBuilder implementation
356 
357         @Override
accept(T t)358         public void accept(T t) {
359             if (count == 0) {
360                 first = t;
361                 count++;
362             }
363             else if (count > 0) {
364                 if (buffer == null) {
365                     buffer = new SpinedBuffer<>();
366                     buffer.accept(first);
367                     count++;
368                 }
369 
370                 buffer.accept(t);
371             }
372             else {
373                 throw new IllegalStateException();
374             }
375         }
376 
add(T t)377         public Stream.Builder<T> add(T t) {
378             accept(t);
379             return this;
380         }
381 
382         @Override
build()383         public Stream<T> build() {
384             int c = count;
385             if (c >= 0) {
386                 // Switch count to negative value signalling the builder is built
387                 count = -count - 1;
388                 // Use this spliterator if 0 or 1 elements, otherwise use
389                 // the spliterator of the spined buffer
390                 return (c < 2) ? StreamSupport.stream(this, false) : StreamSupport.stream(buffer.spliterator(), false);
391             }
392 
393             throw new IllegalStateException();
394         }
395 
396         // Spliterator implementation for 0 or 1 element
397         // count == -1 for no elements
398         // count == -2 for one element held by first
399 
400         @Override
tryAdvance(Consumer<? super T> action)401         public boolean tryAdvance(Consumer<? super T> action) {
402             Objects.requireNonNull(action);
403 
404             if (count == -2) {
405                 action.accept(first);
406                 count = -1;
407                 return true;
408             }
409             else {
410                 return false;
411             }
412         }
413 
414         @Override
forEachRemaining(Consumer<? super T> action)415         public void forEachRemaining(Consumer<? super T> action) {
416             Objects.requireNonNull(action);
417 
418             if (count == -2) {
419                 action.accept(first);
420                 count = -1;
421             }
422         }
423     }
424 
425     static final class IntStreamBuilderImpl
426             extends AbstractStreamBuilderImpl<Integer, Spliterator.OfInt>
427             implements IntStream.Builder, Spliterator.OfInt {
428         // The first element in the stream
429         // valid if count == 1
430         int first;
431 
432         // The first and subsequent elements in the stream
433         // non-null if count == 2
434         SpinedBuffer.OfInt buffer;
435 
436         /**
437          * Constructor for building a stream of 0 or more elements.
438          */
IntStreamBuilderImpl()439         IntStreamBuilderImpl() { }
440 
441         /**
442          * Constructor for a singleton stream.
443          *
444          * @param t the single element
445          */
IntStreamBuilderImpl(int t)446         IntStreamBuilderImpl(int t) {
447             first = t;
448             count = -2;
449         }
450 
451         // StreamBuilder implementation
452 
453         @Override
accept(int t)454         public void accept(int t) {
455             if (count == 0) {
456                 first = t;
457                 count++;
458             }
459             else if (count > 0) {
460                 if (buffer == null) {
461                     buffer = new SpinedBuffer.OfInt();
462                     buffer.accept(first);
463                     count++;
464                 }
465 
466                 buffer.accept(t);
467             }
468             else {
469                 throw new IllegalStateException();
470             }
471         }
472 
473         @Override
build()474         public IntStream build() {
475             int c = count;
476             if (c >= 0) {
477                 // Switch count to negative value signalling the builder is built
478                 count = -count - 1;
479                 // Use this spliterator if 0 or 1 elements, otherwise use
480                 // the spliterator of the spined buffer
481                 return (c < 2) ? StreamSupport.intStream(this, false) : StreamSupport.intStream(buffer.spliterator(), false);
482             }
483 
484             throw new IllegalStateException();
485         }
486 
487         // Spliterator implementation for 0 or 1 element
488         // count == -1 for no elements
489         // count == -2 for one element held by first
490 
491         @Override
tryAdvance(IntConsumer action)492         public boolean tryAdvance(IntConsumer action) {
493             Objects.requireNonNull(action);
494 
495             if (count == -2) {
496                 action.accept(first);
497                 count = -1;
498                 return true;
499             }
500             else {
501                 return false;
502             }
503         }
504 
505         @Override
forEachRemaining(IntConsumer action)506         public void forEachRemaining(IntConsumer action) {
507             Objects.requireNonNull(action);
508 
509             if (count == -2) {
510                 action.accept(first);
511                 count = -1;
512             }
513         }
514     }
515 
516     static final class LongStreamBuilderImpl
517             extends AbstractStreamBuilderImpl<Long, Spliterator.OfLong>
518             implements LongStream.Builder, Spliterator.OfLong {
519         // The first element in the stream
520         // valid if count == 1
521         long first;
522 
523         // The first and subsequent elements in the stream
524         // non-null if count == 2
525         SpinedBuffer.OfLong buffer;
526 
527         /**
528          * Constructor for building a stream of 0 or more elements.
529          */
LongStreamBuilderImpl()530         LongStreamBuilderImpl() { }
531 
532         /**
533          * Constructor for a singleton stream.
534          *
535          * @param t the single element
536          */
LongStreamBuilderImpl(long t)537         LongStreamBuilderImpl(long t) {
538             first = t;
539             count = -2;
540         }
541 
542         // StreamBuilder implementation
543 
544         @Override
accept(long t)545         public void accept(long t) {
546             if (count == 0) {
547                 first = t;
548                 count++;
549             }
550             else if (count > 0) {
551                 if (buffer == null) {
552                     buffer = new SpinedBuffer.OfLong();
553                     buffer.accept(first);
554                     count++;
555                 }
556 
557                 buffer.accept(t);
558             }
559             else {
560                 throw new IllegalStateException();
561             }
562         }
563 
564         @Override
build()565         public LongStream build() {
566             int c = count;
567             if (c >= 0) {
568                 // Switch count to negative value signalling the builder is built
569                 count = -count - 1;
570                 // Use this spliterator if 0 or 1 elements, otherwise use
571                 // the spliterator of the spined buffer
572                 return (c < 2) ? StreamSupport.longStream(this, false) : StreamSupport.longStream(buffer.spliterator(), false);
573             }
574 
575             throw new IllegalStateException();
576         }
577 
578         // Spliterator implementation for 0 or 1 element
579         // count == -1 for no elements
580         // count == -2 for one element held by first
581 
582         @Override
tryAdvance(LongConsumer action)583         public boolean tryAdvance(LongConsumer action) {
584             Objects.requireNonNull(action);
585 
586             if (count == -2) {
587                 action.accept(first);
588                 count = -1;
589                 return true;
590             }
591             else {
592                 return false;
593             }
594         }
595 
596         @Override
forEachRemaining(LongConsumer action)597         public void forEachRemaining(LongConsumer action) {
598             Objects.requireNonNull(action);
599 
600             if (count == -2) {
601                 action.accept(first);
602                 count = -1;
603             }
604         }
605     }
606 
607     static final class DoubleStreamBuilderImpl
608             extends AbstractStreamBuilderImpl<Double, Spliterator.OfDouble>
609             implements DoubleStream.Builder, Spliterator.OfDouble {
610         // The first element in the stream
611         // valid if count == 1
612         double first;
613 
614         // The first and subsequent elements in the stream
615         // non-null if count == 2
616         SpinedBuffer.OfDouble buffer;
617 
618         /**
619          * Constructor for building a stream of 0 or more elements.
620          */
DoubleStreamBuilderImpl()621         DoubleStreamBuilderImpl() { }
622 
623         /**
624          * Constructor for a singleton stream.
625          *
626          * @param t the single element
627          */
DoubleStreamBuilderImpl(double t)628         DoubleStreamBuilderImpl(double t) {
629             first = t;
630             count = -2;
631         }
632 
633         // StreamBuilder implementation
634 
635         @Override
accept(double t)636         public void accept(double t) {
637             if (count == 0) {
638                 first = t;
639                 count++;
640             }
641             else if (count > 0) {
642                 if (buffer == null) {
643                     buffer = new SpinedBuffer.OfDouble();
644                     buffer.accept(first);
645                     count++;
646                 }
647 
648                 buffer.accept(t);
649             }
650             else {
651                 throw new IllegalStateException();
652             }
653         }
654 
655         @Override
build()656         public DoubleStream build() {
657             int c = count;
658             if (c >= 0) {
659                 // Switch count to negative value signalling the builder is built
660                 count = -count - 1;
661                 // Use this spliterator if 0 or 1 elements, otherwise use
662                 // the spliterator of the spined buffer
663                 return (c < 2) ? StreamSupport.doubleStream(this, false) : StreamSupport.doubleStream(buffer.spliterator(), false);
664             }
665 
666             throw new IllegalStateException();
667         }
668 
669         // Spliterator implementation for 0 or 1 element
670         // count == -1 for no elements
671         // count == -2 for one element held by first
672 
673         @Override
tryAdvance(DoubleConsumer action)674         public boolean tryAdvance(DoubleConsumer action) {
675             Objects.requireNonNull(action);
676 
677             if (count == -2) {
678                 action.accept(first);
679                 count = -1;
680                 return true;
681             }
682             else {
683                 return false;
684             }
685         }
686 
687         @Override
forEachRemaining(DoubleConsumer action)688         public void forEachRemaining(DoubleConsumer action) {
689             Objects.requireNonNull(action);
690 
691             if (count == -2) {
692                 action.accept(first);
693                 count = -1;
694             }
695         }
696     }
697 
698     abstract static class ConcatSpliterator<T, T_SPLITR extends Spliterator<T>>
699             implements Spliterator<T> {
700         protected final T_SPLITR aSpliterator;
701         protected final T_SPLITR bSpliterator;
702         // True when no split has occurred, otherwise false
703         boolean beforeSplit;
704         // Never read after splitting
705         final boolean unsized;
706 
ConcatSpliterator(T_SPLITR aSpliterator, T_SPLITR bSpliterator)707         public ConcatSpliterator(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
708             this.aSpliterator = aSpliterator;
709             this.bSpliterator = bSpliterator;
710             beforeSplit = true;
711             // The spliterator is known to be unsized before splitting if the
712             // sum of the estimates overflows.
713             unsized = aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0;
714         }
715 
716         @Override
717         public T_SPLITR trySplit() {
718             @SuppressWarnings("unchecked")
719             T_SPLITR ret = beforeSplit ? aSpliterator : (T_SPLITR) bSpliterator.trySplit();
720             beforeSplit = false;
721             return ret;
722         }
723 
724         @Override
725         public boolean tryAdvance(Consumer<? super T> consumer) {
726             boolean hasNext;
727             if (beforeSplit) {
728                 hasNext = aSpliterator.tryAdvance(consumer);
729                 if (!hasNext) {
730                     beforeSplit = false;
731                     hasNext = bSpliterator.tryAdvance(consumer);
732                 }
733             }
734             else
735                 hasNext = bSpliterator.tryAdvance(consumer);
736             return hasNext;
737         }
738 
739         @Override
740         public void forEachRemaining(Consumer<? super T> consumer) {
741             if (beforeSplit)
742                 aSpliterator.forEachRemaining(consumer);
743             bSpliterator.forEachRemaining(consumer);
744         }
745 
746         @Override
747         public long estimateSize() {
748             if (beforeSplit) {
749                 // If one or both estimates are Long.MAX_VALUE then the sum
750                 // will either be Long.MAX_VALUE or overflow to a negative value
751                 long size = aSpliterator.estimateSize() + bSpliterator.estimateSize();
752                 return (size >= 0) ? size : Long.MAX_VALUE;
753             }
754             else {
755                 return bSpliterator.estimateSize();
756             }
757         }
758 
759         @Override
characteristics()760         public int characteristics() {
761             if (beforeSplit) {
762                 // Concatenation loses DISTINCT and SORTED characteristics
763                 return aSpliterator.characteristics() & bSpliterator.characteristics()
764                        & ~(Spliterator.DISTINCT | Spliterator.SORTED
765                            | (unsized ? Spliterator.SIZED | Spliterator.SUBSIZED : 0));
766             }
767             else {
768                 return bSpliterator.characteristics();
769             }
770         }
771 
772         @Override
getComparator()773         public Comparator<? super T> getComparator() {
774             if (beforeSplit)
775                 throw new IllegalStateException();
776             return bSpliterator.getComparator();
777         }
778 
779         static class OfRef<T> extends ConcatSpliterator<T, Spliterator<T>> {
OfRef(Spliterator<T> aSpliterator, Spliterator<T> bSpliterator)780             OfRef(Spliterator<T> aSpliterator, Spliterator<T> bSpliterator) {
781                 super(aSpliterator, bSpliterator);
782             }
783         }
784 
785         private static abstract class OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
786                 extends ConcatSpliterator<T, T_SPLITR>
787                 implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator)788             private OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
789                 super(aSpliterator, bSpliterator);
790             }
791 
792             @Override
tryAdvance(T_CONS action)793             public boolean tryAdvance(T_CONS action) {
794                 boolean hasNext;
795                 if (beforeSplit) {
796                     hasNext = aSpliterator.tryAdvance(action);
797                     if (!hasNext) {
798                         beforeSplit = false;
799                         hasNext = bSpliterator.tryAdvance(action);
800                     }
801                 }
802                 else
803                     hasNext = bSpliterator.tryAdvance(action);
804                 return hasNext;
805             }
806 
807             @Override
forEachRemaining(T_CONS action)808             public void forEachRemaining(T_CONS action) {
809                 if (beforeSplit)
810                     aSpliterator.forEachRemaining(action);
811                 bSpliterator.forEachRemaining(action);
812             }
813         }
814 
815         static class OfInt
816                 extends ConcatSpliterator.OfPrimitive<Integer, IntConsumer, Spliterator.OfInt>
817                 implements Spliterator.OfInt {
OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator)818             OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator) {
819                 super(aSpliterator, bSpliterator);
820             }
821         }
822 
823         static class OfLong
824                 extends ConcatSpliterator.OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
825                 implements Spliterator.OfLong {
OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator)826             OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator) {
827                 super(aSpliterator, bSpliterator);
828             }
829         }
830 
831         static class OfDouble
832                 extends ConcatSpliterator.OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
833                 implements Spliterator.OfDouble {
OfDouble(Spliterator.OfDouble aSpliterator, Spliterator.OfDouble bSpliterator)834             OfDouble(Spliterator.OfDouble aSpliterator, Spliterator.OfDouble bSpliterator) {
835                 super(aSpliterator, bSpliterator);
836             }
837         }
838     }
839 
840     /**
841      * Given two Runnables, return a Runnable that executes both in sequence,
842      * even if the first throws an exception, and if both throw exceptions, add
843      * any exceptions thrown by the second as suppressed exceptions of the first.
844      */
composeWithExceptions(Runnable a, Runnable b)845     static Runnable composeWithExceptions(Runnable a, Runnable b) {
846         return new Runnable() {
847             @Override
848             public void run() {
849                 try {
850                     a.run();
851                 }
852                 catch (Throwable e1) {
853                     try {
854                         b.run();
855                     }
856                     catch (Throwable e2) {
857                         try {
858                             e1.addSuppressed(e2);
859                         } catch (Throwable ignore) {}
860                     }
861                     throw e1;
862                 }
863                 b.run();
864             }
865         };
866     }
867 
868     /**
869      * Given two streams, return a Runnable that
870      * executes both of their {@link BaseStream#close} methods in sequence,
871      * even if the first throws an exception, and if both throw exceptions, add
872      * any exceptions thrown by the second as suppressed exceptions of the first.
873      */
874     static Runnable composedClose(BaseStream<?, ?> a, BaseStream<?, ?> b) {
875         return new Runnable() {
876             @Override
877             public void run() {
878                 try {
879                     a.close();
880                 }
881                 catch (Throwable e1) {
882                     try {
883                         b.close();
884                     }
885                     catch (Throwable e2) {
886                         try {
887                             e1.addSuppressed(e2);
888                         } catch (Throwable ignore) {}
889                     }
890                     throw e1;
891                 }
892                 b.close();
893             }
894         };
895     }
896 }
897