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 */
25package java.util.stream;
26
27import java.util.Comparator;
28import java.util.Objects;
29import java.util.Spliterator;
30import java.util.function.Consumer;
31import java.util.function.DoubleConsumer;
32import java.util.function.IntConsumer;
33import 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 */
44final class Streams {
45
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
72        RangeIntSpliterator(int from, int upTo, boolean closed) {
73            this(from, upTo, closed ? 1 : 0);
74        }
75
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
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
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
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
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
132        public Comparator<? super Integer> getComparator() {
133            return null;
134        }
135
136        @Override
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
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
196        RangeLongSpliterator(long from, long upTo, boolean closed) {
197            this(from, upTo, closed ? 1 : 0);
198        }
199
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
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
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
244        public long estimateSize() {
245            return upTo - from + last;
246        }
247
248        @Override
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
256        public Comparator<? super Long> getComparator() {
257            return null;
258        }
259
260        @Override
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
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
313        public S trySplit() {
314            return null;
315        }
316
317        @Override
318        public long estimateSize() {
319            return -count - 1;
320        }
321
322        @Override
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         */
343        StreamBuilderImpl() { }
344
345        /**
346         * Constructor for a singleton stream.
347         *
348         * @param t the single element
349         */
350        StreamBuilderImpl(T t) {
351            first = t;
352            count = -2;
353        }
354
355        // StreamBuilder implementation
356
357        @Override
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
377        public Stream.Builder<T> add(T t) {
378            accept(t);
379            return this;
380        }
381
382        @Override
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
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
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         */
439        IntStreamBuilderImpl() { }
440
441        /**
442         * Constructor for a singleton stream.
443         *
444         * @param t the single element
445         */
446        IntStreamBuilderImpl(int t) {
447            first = t;
448            count = -2;
449        }
450
451        // StreamBuilder implementation
452
453        @Override
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
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
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
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         */
530        LongStreamBuilderImpl() { }
531
532        /**
533         * Constructor for a singleton stream.
534         *
535         * @param t the single element
536         */
537        LongStreamBuilderImpl(long t) {
538            first = t;
539            count = -2;
540        }
541
542        // StreamBuilder implementation
543
544        @Override
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
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
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
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         */
621        DoubleStreamBuilderImpl() { }
622
623        /**
624         * Constructor for a singleton stream.
625         *
626         * @param t the single element
627         */
628        DoubleStreamBuilderImpl(double t) {
629            first = t;
630            count = -2;
631        }
632
633        // StreamBuilder implementation
634
635        @Override
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
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
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
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
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
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
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>> {
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> {
788            private OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
789                super(aSpliterator, bSpliterator);
790            }
791
792            @Override
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
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 {
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 {
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 {
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     */
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