Home | History | Annotate | Download | only in stream
      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 
     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