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