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