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