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