Streams.java revision 12745:f068a4ffddd2
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;
34import jdk.internal.HotSpotIntrinsicCandidate;
35
36/**
37 * Utility methods for operating on and creating streams.
38 *
39 * <p>Unless otherwise stated, streams are created as sequential streams.  A
40 * sequential stream can be transformed into a parallel stream by calling the
41 * {@code parallel()} method on the created stream.
42 *
43 * @since 1.8
44 */
45final class Streams {
46
47    private Streams() {
48        throw new Error("no instances");
49    }
50
51    /**
52     * An object instance representing no value, that cannot be an actual
53     * data element of a stream.  Used when processing streams that can contain
54     * {@code null} elements to distinguish between a {@code null} value and no
55     * value.
56     */
57    static final Object NONE = new Object();
58
59    /**
60     * An {@code int} range spliterator.
61     */
62    static final class RangeIntSpliterator implements Spliterator.OfInt {
63        // Can never be greater that upTo, this avoids overflow if upper bound
64        // is Integer.MAX_VALUE
65        // All elements are traversed if from == upTo & last == 0
66        private int from;
67        private final int upTo;
68        // 1 if the range is closed and the last element has not been traversed
69        // Otherwise, 0 if the range is open, or is a closed range and all
70        // elements have been traversed
71        private int last;
72
73        RangeIntSpliterator(int from, int upTo, boolean closed) {
74            this(from, upTo, closed ? 1 : 0);
75        }
76
77        private RangeIntSpliterator(int from, int upTo, int last) {
78            this.from = from;
79            this.upTo = upTo;
80            this.last = last;
81        }
82
83        @Override
84        public boolean tryAdvance(IntConsumer consumer) {
85            Objects.requireNonNull(consumer);
86
87            final int i = from;
88            if (i < upTo) {
89                from++;
90                consumer.accept(i);
91                return true;
92            }
93            else if (last > 0) {
94                last = 0;
95                consumer.accept(i);
96                return true;
97            }
98            return false;
99        }
100
101        @Override
102        @HotSpotIntrinsicCandidate
103        public void forEachRemaining(IntConsumer consumer) {
104            Objects.requireNonNull(consumer);
105
106            int i = from;
107            final int hUpTo = upTo;
108            int hLast = last;
109            from = upTo;
110            last = 0;
111            while (i < hUpTo) {
112                consumer.accept(i++);
113            }
114            if (hLast > 0) {
115                // Last element of closed range
116                consumer.accept(i);
117            }
118        }
119
120        @Override
121        public long estimateSize() {
122            // Ensure ranges of size > Integer.MAX_VALUE report the correct size
123            return ((long) upTo) - from + last;
124        }
125
126        @Override
127        public int characteristics() {
128            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
129                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
130                   Spliterator.DISTINCT | Spliterator.SORTED;
131        }
132
133        @Override
134        public Comparator<? super Integer> getComparator() {
135            return null;
136        }
137
138        @Override
139        public Spliterator.OfInt trySplit() {
140            long size = estimateSize();
141            return size <= 1
142                   ? null
143                   // Left split always has a half-open range
144                   : new RangeIntSpliterator(from, from = from + splitPoint(size), 0);
145        }
146
147        /**
148         * The spliterator size below which the spliterator will be split
149         * at the mid-point to produce balanced splits. Above this size the
150         * spliterator will be split at a ratio of
151         * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
152         * to produce right-balanced splits.
153         *
154         * <p>Such splitting ensures that for very large ranges that the left
155         * side of the range will more likely be processed at a lower-depth
156         * than a balanced tree at the expense of a higher-depth for the right
157         * side of the range.
158         *
159         * <p>This is optimized for cases such as IntStream.range(0, Integer.MAX_VALUE)
160         * that is likely to be augmented with a limit operation that limits the
161         * number of elements to a count lower than this threshold.
162         */
163        private static final int BALANCED_SPLIT_THRESHOLD = 1 << 24;
164
165        /**
166         * The split ratio of the left and right split when the spliterator
167         * size is above BALANCED_SPLIT_THRESHOLD.
168         */
169        private static final int RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
170
171        private int splitPoint(long size) {
172            int d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
173            // Cast to int is safe since:
174            //   2 <= size < 2^32
175            //   2 <= d <= 8
176            return (int) (size / d);
177        }
178    }
179
180    /**
181     * A {@code long} range spliterator.
182     *
183     * This implementation cannot be used for ranges whose size is greater
184     * than Long.MAX_VALUE
185     */
186    static final class RangeLongSpliterator implements Spliterator.OfLong {
187        // Can never be greater that upTo, this avoids overflow if upper bound
188        // is Long.MAX_VALUE
189        // All elements are traversed if from == upTo & last == 0
190        private long from;
191        private final long upTo;
192        // 1 if the range is closed and the last element has not been traversed
193        // Otherwise, 0 if the range is open, or is a closed range and all
194        // elements have been traversed
195        private int last;
196
197        RangeLongSpliterator(long from, long upTo, boolean closed) {
198            this(from, upTo, closed ? 1 : 0);
199        }
200
201        private RangeLongSpliterator(long from, long upTo, int last) {
202            assert upTo - from + last > 0;
203            this.from = from;
204            this.upTo = upTo;
205            this.last = last;
206        }
207
208        @Override
209        public boolean tryAdvance(LongConsumer consumer) {
210            Objects.requireNonNull(consumer);
211
212            final long i = from;
213            if (i < upTo) {
214                from++;
215                consumer.accept(i);
216                return true;
217            }
218            else if (last > 0) {
219                last = 0;
220                consumer.accept(i);
221                return true;
222            }
223            return false;
224        }
225
226        @Override
227        public void forEachRemaining(LongConsumer consumer) {
228            Objects.requireNonNull(consumer);
229
230            long i = from;
231            final long hUpTo = upTo;
232            int hLast = last;
233            from = upTo;
234            last = 0;
235            while (i < hUpTo) {
236                consumer.accept(i++);
237            }
238            if (hLast > 0) {
239                // Last element of closed range
240                consumer.accept(i);
241            }
242        }
243
244        @Override
245        public long estimateSize() {
246            return upTo - from + last;
247        }
248
249        @Override
250        public int characteristics() {
251            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
252                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
253                   Spliterator.DISTINCT | Spliterator.SORTED;
254        }
255
256        @Override
257        public Comparator<? super Long> getComparator() {
258            return null;
259        }
260
261        @Override
262        public Spliterator.OfLong trySplit() {
263            long size = estimateSize();
264            return size <= 1
265                   ? null
266                   // Left split always has a half-open range
267                   : new RangeLongSpliterator(from, from = from + splitPoint(size), 0);
268        }
269
270        /**
271         * The spliterator size below which the spliterator will be split
272         * at the mid-point to produce balanced splits. Above this size the
273         * spliterator will be split at a ratio of
274         * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
275         * to produce right-balanced splits.
276         *
277         * <p>Such splitting ensures that for very large ranges that the left
278         * side of the range will more likely be processed at a lower-depth
279         * than a balanced tree at the expense of a higher-depth for the right
280         * side of the range.
281         *
282         * <p>This is optimized for cases such as LongStream.range(0, Long.MAX_VALUE)
283         * that is likely to be augmented with a limit operation that limits the
284         * number of elements 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 abstract static 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 abstract static 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