1 /*- 2 * #%L 3 * io.earcam.unexceptional 4 * %% 5 * Copyright (C) 2016 - 2017 earcam 6 * %% 7 * SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT) 8 * 9 * You <b>must</b> choose to accept, in full - any individual or combination of 10 * the following licenses: 11 * <ul> 12 * <li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li> 13 * <li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li> 14 * <li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li> 15 * <li><a href="https://opensource.org/licenses/MIT">MIT</a></li> 16 * </ul> 17 * #L% 18 */ 19 package io.earcam.unexceptional; 20 21 import static java.util.Collections.unmodifiableMap; 22 23 import java.io.IOException; 24 import java.io.Serializable; 25 import java.io.UncheckedIOException; 26 import java.lang.Thread.UncaughtExceptionHandler; 27 import java.lang.reflect.InvocationTargetException; 28 import java.lang.reflect.UndeclaredThrowableException; 29 import java.net.MalformedURLException; 30 import java.net.URI; 31 import java.net.URISyntaxException; 32 import java.net.URL; 33 import java.net.URLStreamHandler; 34 import java.security.GeneralSecurityException; 35 import java.util.Comparator; 36 import java.util.HashMap; 37 import java.util.HashSet; 38 import java.util.Map; 39 import java.util.Set; 40 import java.util.concurrent.Callable; 41 import java.util.function.BiConsumer; 42 import java.util.function.BiFunction; 43 import java.util.function.BinaryOperator; 44 import java.util.function.Consumer; 45 import java.util.function.Function; 46 import java.util.function.IntConsumer; 47 import java.util.function.Predicate; 48 import java.util.function.Supplier; 49 import java.util.function.ToDoubleFunction; 50 import java.util.function.ToIntBiFunction; 51 import java.util.function.ToIntFunction; 52 import java.util.function.ToLongFunction; 53 import java.util.stream.Stream; 54 55 /** 56 * <p> 57 * Static utility for easy conversion of checked exceptions, and invocation of methods declaring checked exceptions. 58 * </p> 59 * 60 * <p> 61 * There are many cases where you <i>know</i>, within a given context that a checked exception will not be raised, but 62 * if it is, then it's certainly <i>game over</i>. An example being URLs in server configuration. 63 * </p> 64 * 65 * <p> 66 * The functionality centres around {@link java.util.function} given their beautifully broad application. 67 * </p> 68 * 69 * <p> 70 * In addition, common standard library <i>annoyances</i> are included; e.g. {@link URL}, {@link URI}, and highly 71 * concise (re-read as terse one-liner - arguably laconic over expressive) for common IO streams usage. 72 * </p> 73 * 74 * <p> 75 * When dealing with {@link Stream} from an IO source (e.g. the file system), it may be preferable (to pay a 76 * performance cost due to wrapping) and use {@link EmeticStream} which mirrors {@link Stream} functionality 77 * but with checked equivalent types. 78 * </p> 79 * 80 * <h1>Exceptional</h1> 81 * <b>/ɪkˈsɛpʃ(ə)n(ə)l,ɛkˈsɛpʃ(ə)n(ə)l/</b> 82 * <p> 83 * <i>adjective:</i> 84 * </p> 85 * <p> 86 * 1. unusual; not typical. 87 * </p> 88 */ 89 /* @javax.annotation.ParametersAreNonnullByDefault */ 90 /* @edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault */ 91 /* @net.jcip.annotations.Immutable */ 92 @SuppressWarnings({ 93 "squid:S1905", // SonarQube false positives 94 "squid:S1181" // SonarQube necessary evil 95 }) 96 public final class Exceptional implements Serializable { 97 98 private static final long serialVersionUID = -1350140594550206145L; 99 100 private static final Map<Class<? extends Throwable>, Function<Throwable, RuntimeException>> UNCHECK_MAP; 101 102 static { 103 Map<Class<? extends Throwable>, Function<Throwable, RuntimeException>> map = new HashMap<>(); 104 // @formatter:off 105 map.put(ReflectiveOperationException.class, e -> new UncheckedReflectiveException((ReflectiveOperationException)e)); 106 map.put( GeneralSecurityException.class, e -> new UncheckedSecurityException((GeneralSecurityException)e)); 107 map.put( InterruptedException.class, e -> new UncheckedInterruptException((InterruptedException)e)); 108 map.put( URISyntaxException.class, e -> new UncheckedUriSyntaxException((URISyntaxException)e)); 109 map.put( RuntimeException.class, RuntimeException.class::cast); 110 map.put( IOException.class, e -> new UncheckedIOException((IOException)e)); 111 // @formatter:on 112 113 UNCHECK_MAP = unmodifiableMap(map); 114 } 115 116 /** 117 * An {@link UncaughtExceptionHandler} that simply rethrows, 118 * wrapping in an appropriate unchecked if necessary 119 * 120 * @since 0.2.0 121 */ 122 public static final UncaughtExceptionHandler RETHROWING = (t, e) -> Exceptional.rethrow(e); 123 124 /** 125 * An {@link UncaughtExceptionHandler} that simply swallows <i>all</i> exceptions, 126 * except subclasses of {@link Error}, which are rethrown. 127 * 128 * @since 0.2.0 129 */ 130 public static final UncaughtExceptionHandler SWALLOWING = (t, e) -> Exceptional.swallow(e); 131 132 133 private Exceptional() 134 { 135 throw new IllegalStateException("Why on earth would you want to instantiate this?"); 136 } 137 138 139 /** 140 * @param earl the text URL 141 * @return a {@link URL} representation 142 * 143 * @since 0.2.0 144 */ 145 public static URL url(CharSequence earl) 146 { 147 try { 148 return new URL(earl.toString()); 149 } catch(MalformedURLException e) { 150 throw uncheck(e); 151 } 152 } 153 154 155 /** 156 * @param protocol e.g. https, ftp, sctp 157 * @param host hostname or IP 158 * @param port 0 to 65536 159 * @param path the "file" portion of the URL 160 * @param handler optional URLStreamHandler 161 * @return a {@link URL} representation 162 * 163 * @since 0.2.0 164 */ 165 public static URL url(String protocol, String host, int port, String path, /* @Nullable */ URLStreamHandler handler) 166 { 167 try { 168 return new URL(protocol, host, port, path, handler); 169 } catch(MalformedURLException e) { 170 throw uncheck(e); 171 } 172 } 173 174 175 /** 176 * @param ʊri the text URI (as Earl is to URL, so ʊri (as in Uri Geller) is to URI) 177 * @return a {@link URI} representation 178 * 179 * @since 0.2.0 180 */ 181 @SuppressWarnings("squid:S00117") // utf8 in a parameter name is fine by me 182 public static URI uri(CharSequence ʊri) 183 { 184 try { 185 return new URI(ʊri.toString()); 186 } catch(URISyntaxException e) { 187 throw uncheck(e); 188 } 189 } 190 191 192 /** 193 * Invokes {@link URL#toURI()}, catching any {@link URISyntaxException} and rethrowing 194 * wrapped as {@link UncheckedUriSyntaxException} 195 * 196 * @param earl the {@link URL} to convert 197 * @return the {@link URI} form of the <code>earl</code> argument 198 * 199 * @since 0.3.0 200 */ 201 public static URI uri(URL earl) 202 { 203 try { 204 return earl.toURI(); 205 } catch(URISyntaxException e) { 206 throw uncheck(e); 207 } 208 } 209 210 211 /** 212 * Will regurgitate any {@link Error} - otherwise will dutifully and silently <i>swallow</i> whole. 213 * Gulping of {@link InterruptedException}s will result in the current {@link Thread}'s interrupt 214 * flag being reset. 215 * 216 * <b>Caution</b>: used carelessly/incorrectly this foul method will inevitably lead to a frustrating 217 * debugging session resulting in plenty of "doh"/"wtf" but never a "eureka" moment. Shooting of 218 * messenger is in breach of license terms. 219 * 220 * @param caught the caught unmentionable 221 * 222 * @since 0.2.0 223 */ 224 public static void swallow(Throwable caught) 225 { 226 resetIfInterrupt(caught); 227 if(caught instanceof Error) { 228 throw (Error) caught; 229 } 230 } 231 232 233 /** 234 * Catching an {@link InterruptedException} clears the interrupt flag, 235 * this merely resets the flag IFF the <code>thrown</code> parameter is 236 * an instance of {@link InterruptedException}. 237 * 238 * @param thrown possible {@link InterruptedException} 239 * 240 * @since 0.2.0 241 */ 242 public static void resetIfInterrupt(Throwable thrown) 243 { 244 if(thrown instanceof InterruptedException) { 245 Thread.currentThread().interrupt(); 246 } 247 } 248 249 250 /** 251 * Directly rethrows {@link Error}s or {@link RuntimeException}s, wraps 252 * checked exceptions appropriately 253 * 254 * @param thrown the caught throwable to be rethrown as unchecked 255 * @return actually nothing, this just allows you to write {@code throw Exceptional.rethrow(e)} for methods than 256 * have return values. 257 * 258 * @see #throwAsUnchecked(Throwable) 259 * 260 * @since 0.2.0 261 */ 262 public static RuntimeException rethrow(Throwable thrown) 263 { 264 if(thrown instanceof Error) { 265 throw (Error) thrown; 266 } 267 throw uncheck(thrown); 268 } 269 270 271 /** 272 * Invokes {@link CheckedRunnable#run()} catching any checked 273 * {@link Exception}s rethrowing them as unchecked. 274 * 275 * @param runnable the checked runnable to run 276 * 277 * @since 0.2.0 278 */ 279 public static void run(CheckedRunnable<?> runnable) 280 { 281 try { 282 runnable.run(); 283 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 284 throw error; 285 } catch(Throwable thrown) { 286 throw uncheck(thrown); 287 } 288 } 289 290 291 /** 292 * Convert a {@link CheckedRunnable} into a {@link Runnable} 293 * 294 * @param runnable the checked runnable to wrap 295 * @return an unchecked wrapper around the <code>runnable</code> argument 296 * 297 * @since 0.2.0 298 */ 299 public static Runnable uncheckRunnable(CheckedRunnable<?> runnable) 300 { 301 return () -> run(runnable); 302 } 303 304 305 /** 306 * Invokes {@link Callable#call()} catching any checked 307 * {@link Exception}s rethrowing as unchecked. 308 * 309 * @param <T> the return type of the {@link Callable} 310 * 311 * @param callable the {@link Callable} to execute 312 * @return the result of calling the {@link Callable} 313 * 314 * @since 0.2.0 315 */ 316 public static <T> T call(Callable<T> callable) 317 { 318 try { 319 return callable.call(); 320 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 321 throw error; 322 } catch(Throwable thrown) { 323 throw uncheck(thrown); 324 } 325 } 326 327 328 /** 329 * <p> 330 * Converts {@link Throwable}s to {@link RuntimeException}s. 331 * </p> 332 * <p> 333 * If the supplied {@link Throwable} is already a {@link RuntimeException}, then it's simply cast and returned. 334 * </p> 335 * <p> 336 * {@link Error} subclasses will be wrapped in an {@link UncheckedException}. 337 * </p> 338 * <p> 339 * The interrupt flag will be reset IFF {@code caught instanceof InterruptedException} 340 * </p> 341 * 342 * @param caught any {@link Throwable} 343 * @return a {@link RuntimeException}, typically a subclass of {@link UncheckedException} or an 344 * {@link UncheckedIOException} 345 * @see #rethrow(Throwable) 346 * 347 * @since 0.2.0 348 */ 349 public static RuntimeException uncheck(Throwable caught) 350 { 351 return UNCHECK_MAP.entrySet().stream() 352 .filter(e -> e.getKey().isInstance(caught)) 353 .map(e -> e.getValue().apply(caught)) 354 .findFirst() 355 .orElseGet(() -> new UncheckedException(caught)); 356 } 357 358 359 /** 360 * Converts {@link CheckedConsumer} to {@link Consumer} 361 * 362 * @param <T> the consumed type 363 * 364 * @param consumer a consumer that declares checked exception(s) 365 * @return a vanilla {@link java.util.function.Consumer} 366 * 367 * @since 0.2.0 368 */ 369 @SuppressWarnings("unchecked") 370 public static <T> Consumer<T> uncheckConsumer(CheckedConsumer<T, ?> consumer) 371 { 372 return (Consumer<T> & Serializable) t -> Exceptional.accept(consumer, t); 373 } 374 375 376 /** 377 * Invokes {@link CheckedConsumer#accept(Object)} catching any checked 378 * {@link Exception}s rethrowing as unchecked. 379 * 380 * @param <T> the consumed type 381 * 382 * @param consumer the consumer of the {@code value} 383 * @param value the value to be consumed 384 * 385 * @since 0.2.0 386 */ 387 public static <T> void accept(CheckedConsumer<T, ?> consumer, T value) 388 { 389 try { 390 consumer.accept(value); 391 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 392 throw error; 393 } catch(Throwable thrown) { 394 throw uncheck(thrown); 395 } 396 } 397 398 399 /** 400 * Converts {@link CheckedIntConsumer} to {@link IntConsumer} 401 * 402 * @param consumer a consumer of primitive integer that declares checked exception(s) 403 * @return a vanilla {@link java.util.function.IntConsumer} 404 * 405 * @since 0.5.0 406 */ 407 public static IntConsumer uncheckIntConsumer(CheckedIntConsumer<?> consumer) 408 { 409 return (IntConsumer & Serializable) t -> Exceptional.accept(consumer, t); 410 } 411 412 413 /** 414 * Invokes {@link CheckedIntConsumer#accept(int)} catching any checked 415 * {@link Exception}s rethrowing as unchecked. 416 * 417 * @param consumer the consumer of the {@code int value} 418 * @param value the value to be consumed 419 * 420 * @since 0.5.0 421 */ 422 public static void accept(CheckedIntConsumer<?> consumer, int value) 423 { 424 try { 425 consumer.accept(value); 426 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 427 throw error; 428 } catch(Throwable thrown) { 429 throw uncheck(thrown); 430 } 431 } 432 433 434 /** 435 * Convert a {@link CheckedBiConsumer} into a {@link BiConsumer}. 436 * 437 * @param <T> first argument type 438 * @param <U> last argument type 439 * 440 * @param consumer the checked consumer 441 * @return an unchecked consumer wrapping the {@code consumer} argument 442 * 443 * @since 0.2.0 444 */ 445 @SuppressWarnings("unchecked") 446 public static <T, U> BiConsumer<T, U> uncheckBiConsumer(CheckedBiConsumer<T, U, ?> consumer) 447 { 448 return (BiConsumer<T, U> & Serializable) (t, u) -> Exceptional.accept(consumer, t, u); 449 } 450 451 452 /** 453 * Invokes {@link CheckedConsumer#accept(Object)} catching any checked 454 * {@link Exception}s rethrowing as unchecked. 455 * 456 * @param <T> first argument type 457 * @param <U> last argument type 458 * 459 * @param consumer the consumer of the {@code value} 460 * @param t first argument to be consumed 461 * @param u last argument to be consumed 462 * 463 * @since 0.2.0 464 */ 465 public static <T, U> void accept(CheckedBiConsumer<T, U, ?> consumer, T t, U u) 466 { 467 try { 468 consumer.accept(t, u); 469 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 470 throw error; 471 } catch(Throwable thrown) { 472 throw uncheck(thrown); 473 } 474 } 475 476 477 /** 478 * Converts a {@link CheckedFunction} into a {@link Function}. 479 * 480 * @param <T> argument type 481 * @param <R> return type 482 * 483 * @param function the checked function 484 * @return an unchecked function wrapping the {@code function} argument. 485 * 486 * @since 0.2.0 487 */ 488 @SuppressWarnings("unchecked") 489 public static <T, R> Function<T, R> uncheckFunction(CheckedFunction<T, R, ?> function) 490 { 491 return (Function<T, R> & Serializable) t -> Exceptional.apply(function, t); 492 } 493 494 495 /** 496 * Invokes {@link CheckedFunction#apply(Object)} catching any checked 497 * {@link Exception}s rethrowing as unchecked. 498 * 499 * @param <T> argument type 500 * @param <R> return type 501 * 502 * @param function the checked function to invoke with the {@code argument} 503 * @param argument the argument to apply to the function 504 * @return the result of applying {@code argument} to {@code function} 505 * 506 * @since 0.2.0 507 */ 508 public static <T, R> R apply(CheckedFunction<T, R, ?> function, T argument) 509 { 510 try { 511 return function.apply(argument); 512 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 513 throw error; 514 } catch(Throwable thrown) { 515 throw uncheck(thrown); 516 } 517 } 518 519 520 /** 521 * Convert a {@link CheckedBiFunction} into a {@link BiFunction}. 522 * 523 * @param <T> first argument type 524 * @param <U> last argument type 525 * @param <R> return type 526 * 527 * @param function the checked bi-function 528 * @return an unchecked bi-function wrapping the {@code function} argument. 529 * 530 * @since 0.2.0 531 */ 532 @SuppressWarnings("unchecked") 533 public static <T, U, R> BiFunction<T, U, R> uncheckBiFunction(CheckedBiFunction<T, U, R, ?> function) 534 { 535 return (BiFunction<T, U, R> & Serializable) (t, u) -> Exceptional.apply(function, t, u); 536 } 537 538 539 /** 540 * Invokes {@link CheckedFunction#apply(Object)} catching any checked 541 * {@link Exception}s rethrowing as unchecked. 542 * 543 * @param <T> first argument type 544 * @param <U> last argument type 545 * @param <R> return type 546 * 547 * @param function the checked function to invoke with the {@code argument} 548 * @param t the first argument to apply to the function 549 * @param u the second argument to apply to the function 550 * @return the result of applying {@code function} to the arguments {@code t} and {@code u} 551 * 552 * @since 0.2.0 553 */ 554 public static <T, U, R> R apply(CheckedBiFunction<T, U, R, ?> function, T t, U u) 555 { 556 try { 557 return function.apply(t, u); 558 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 559 throw error; 560 } catch(Throwable thrown) { 561 throw uncheck(thrown); 562 } 563 } 564 565 566 /** 567 * Converts a {@link CheckedBinaryOperator} into a {@link BinaryOperator}. 568 * 569 * @param <T> operator type 570 * 571 * @param operator the checked binary operator 572 * @return and unchecked wrapper around the {@code operator} argument 573 * 574 * @since 0.2.0 575 */ 576 @SuppressWarnings("unchecked") 577 public static <T> BinaryOperator<T> uncheckBinaryOperator(CheckedBinaryOperator<T, ?> operator) 578 { 579 return (BinaryOperator<T> & Serializable) (a, b) -> Exceptional.apply(operator, a, b); 580 } 581 582 583 /** 584 * Converts a {@link CheckedToDoubleFunction} into a {@link ToDoubleFunction}. 585 * 586 * @param <T> argument type 587 * 588 * @param function the checked to-double-function 589 * @return an unchecked to-double-function wrapping the {@code function} argument. 590 * 591 * @since 0.2.0 592 */ 593 @SuppressWarnings("unchecked") 594 public static <T> ToDoubleFunction<T> uncheckToDoubleFunction(CheckedToDoubleFunction<T, ?> function) 595 { 596 return (ToDoubleFunction<T> & Serializable) t -> Exceptional.applyAsDouble(function, t); 597 } 598 599 600 /** 601 * Invokes {@link CheckedToDoubleFunction#applyAsDouble(Object)} catching any checked 602 * {@link Exception}s rethrowing as unchecked. 603 * 604 * @param <T> argument type 605 * 606 * @param function the checked to-double function 607 * @param t the function argument 608 * @return the double result of applying the {@code function} to argument {@code t} 609 * 610 * @since 0.2.0 611 */ 612 public static <T> double applyAsDouble(CheckedToDoubleFunction<T, ?> function, T t) 613 { 614 try { 615 return function.applyAsDouble(t); 616 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 617 throw error; 618 } catch(Throwable thrown) { 619 throw uncheck(thrown); 620 } 621 } 622 623 624 /** 625 * Converts a {@link CheckedToIntFunction} into a {@link ToIntFunction}. 626 * 627 * @param <T> argument type 628 * 629 * @param function the checked to-int-function 630 * @return an unchecked to-int-function wrapping the {@code function} argument. 631 * 632 * @since 0.2.0 633 */ 634 @SuppressWarnings("unchecked") 635 public static <T> ToIntFunction<T> uncheckToIntFunction(CheckedToIntFunction<T, ?> function) 636 { 637 return (ToIntFunction<T> & Serializable) t -> Exceptional.applyAsInt(function, t); 638 } 639 640 641 /** 642 * Invokes {@link CheckedToIntFunction#applyAsInt(Object)} catching any checked 643 * {@link Exception}s rethrowing as unchecked. 644 * 645 * @param <T> argument type 646 * 647 * @param function the checked to-int function 648 * @param t the function argument 649 * @return the int result of applying the {@code function} to argument {@code t} 650 * 651 * @since 0.2.0 652 */ 653 public static <T> int applyAsInt(CheckedToIntFunction<T, ?> function, T t) 654 { 655 try { 656 return function.applyAsInt(t); 657 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 658 throw error; 659 } catch(Throwable thrown) { 660 throw uncheck(thrown); 661 } 662 } 663 664 665 /** 666 * Converts a {@link CheckedToLongFunction} into a {@link ToLongFunction}. 667 * 668 * @param <T> argument type 669 * 670 * @param function the checked to-long-function 671 * @return an unchecked to-long-function wrapping the {@code function} argument. 672 * 673 * @since 0.2.0 674 */ 675 @SuppressWarnings("unchecked") 676 public static <T> ToLongFunction<T> uncheckToLongFunction(CheckedToLongFunction<T, ?> function) 677 { 678 return (ToLongFunction<T> & Serializable) t -> Exceptional.applyAsLong(function, t); 679 } 680 681 682 /** 683 * Invokes {@link CheckedToLongFunction#applyAsLong(Object)} catching any checked 684 * {@link Exception}s rethrowing as unchecked. 685 * 686 * @param <T> argument type 687 * 688 * @param function the checked to-long function 689 * @param t the function argument 690 * @return the long result of applying the {@code function} to argument {@code t} 691 * 692 * @since 0.2.0 693 */ 694 public static <T> long applyAsLong(CheckedToLongFunction<T, ?> function, T t) 695 { 696 try { 697 return function.applyAsLong(t); 698 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 699 throw error; 700 } catch(Throwable thrown) { 701 throw uncheck(thrown); 702 } 703 } 704 705 706 /** 707 * Convert a {@link CheckedSupplier} into an unchecked {@link Supplier}. 708 * 709 * @param <T> supplied type 710 * 711 * @param supplier the checked supplier to wrap 712 * @return an unchecked supplier wrapping the {@code supplier} argument 713 * 714 * @since 0.2.0 715 */ 716 @SuppressWarnings("unchecked") 717 public static <T> Supplier<T> uncheckSupplier(CheckedSupplier<T, ?> supplier) 718 { 719 return (Supplier<T> & Serializable) () -> Exceptional.get(supplier); 720 } 721 722 723 /** 724 * Invokes {@link CheckedSupplier#get()} catching any checked 725 * {@link Exception}s rethrowing as unchecked. 726 * 727 * @param <T> supplied type 728 * 729 * @param supplier the checked supplier 730 * @return the result as supplied from the {@code supplier} argument 731 * 732 * @since 0.2.0 733 */ 734 public static <T> T get(CheckedSupplier<T, ?> supplier) 735 { 736 try { 737 return supplier.get(); 738 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 739 throw error; 740 } catch(Throwable thrown) { 741 throw uncheck(thrown); 742 } 743 } 744 745 746 /** 747 * Converts a {@link CheckedPredicate} into a {@link Predicate}. 748 * 749 * @param <T> tested type 750 * 751 * @param predicate the checked predicate to wrap 752 * @return an unchecked predicate wrapping the {@code predicate} argument 753 * 754 * @since 0.2.0 755 */ 756 @SuppressWarnings("unchecked") 757 public static <T> Predicate<T> uncheckPredicate(CheckedPredicate<T, ?> predicate) 758 { 759 return (Predicate<T> & Serializable) t -> Exceptional.test(predicate, t); 760 } 761 762 763 /** 764 * Invokes {@link CheckedPredicate#test(Object)} catching any checked 765 * {@link Exception}s rethrowing as unchecked. 766 * 767 * @param <T> tested type 768 * 769 * @param predicate the checked predicate to test on the {@code value} 770 * @param value the value to be tested 771 * @return true IFF value passes predicate's test 772 * 773 * @since 0.2.0 774 */ 775 public static <T> boolean test(CheckedPredicate<T, ?> predicate, T value) 776 { 777 try { 778 return predicate.test(value); 779 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 780 throw error; 781 } catch(Throwable thrown) { 782 throw uncheck(thrown); 783 } 784 } 785 786 787 /** 788 * Converts a {@link CheckedComparator} into an unchecked {@link Comparator}. 789 * 790 * @param <T> compared type 791 * 792 * @param comparator the checked comparator to wrap 793 * @return an unchecked comparator wrapping the {@code comparator} argument 794 * 795 * @since 0.2.0 796 */ 797 @SuppressWarnings("unchecked") 798 public static <T> Comparator<T> uncheckComparator(CheckedComparator<T, ?> comparator) 799 { 800 return (Comparator<T> & Serializable) (a, b) -> Exceptional.applyAsInt(comparator, a, b); 801 } 802 803 804 /** 805 * Converts a {@link CheckedToIntBiFunction} into an unchecked {@link ToIntBiFunction}. 806 * 807 * @param <T> first argument type 808 * @param <U> last argument type 809 * 810 * @param function the checked bi-function 811 * @return an unchecked bi-function 812 */ 813 @SuppressWarnings("unchecked") 814 public static <T, U> ToIntBiFunction<T, U> uncheckToIntBiFunction(CheckedToIntBiFunction<T, U, ?> function) 815 { 816 return (ToIntBiFunction<T, U> & Serializable) (a, b) -> Exceptional.applyAsInt(function, a, b); 817 } 818 819 820 /** 821 * Invokes {@link CheckedFunction#apply(Object)} catching any checked 822 * {@link Exception}s rethrowing as unchecked. 823 * 824 * @param <T> first argument type 825 * @param <U> last argument type 826 * 827 * @param function the checked function to invoke with the {@code argument} 828 * @param t the first argument to apply to the function 829 * @param u the second argument to apply to the function 830 * @return the result of applying {@code function} to the arguments {@code t} and {@code u} 831 * 832 * @since 0.2.0 833 */ 834 public static <T, U> int applyAsInt(CheckedToIntBiFunction<T, U, ?> function, T t, U u) 835 { 836 try { 837 return function.applyAsInt(t, u); 838 } catch(Error error) { // repeated tedious (likewise with tests) as Jacoco does not add enough probes 839 throw error; 840 } catch(Throwable thrown) { 841 throw uncheck(thrown); 842 } 843 } 844 845 846 /** 847 * <p> 848 * This fugly method relies on erasure to trick the compiler, allowing you to throw any checked 849 * exception without declaring so on the surrounding method. You are almost certainly better off 850 * using {@link #rethrow(Throwable)}. 851 * </p> 852 * <p> 853 * <b>Note</b>: this may well become an obsolete hack in future versions of Java if generics change. 854 * </p> 855 * 856 * @param throwable the {@link Throwable} to be thrown 857 * @return this alleged return will never be received, but useful in that 858 * you may write <code>throws {@link Exceptional#throwAsUnchecked(Throwable)};</code> 859 * to placate the compiler WRT non-void method returns, and ensure Static Code 860 * Analysis doesn't accuse you of swallowing the exception. 861 * 862 * @since 0.2.0 863 * 864 * @see #rethrow(Throwable) 865 */ 866 public static RuntimeException throwAsUnchecked(Throwable throwable) 867 { 868 resetIfInterrupt(throwable); 869 return Exceptional.<RuntimeException> eraseAndThrow(throwable); 870 } 871 872 873 @SuppressWarnings("unchecked") 874 private static <T extends Throwable> RuntimeException eraseAndThrow(Throwable throwable) throws T 875 { 876 throw (T) throwable; 877 } 878 879 880 /** 881 * <p> 882 * Attempts to unwrap invocation and unchecked exceptions to their underlying cause. 883 * Unwrapping is recursively applied. The original wrapper exception is added to the suppressed 884 * throwables of the returned unwrapped throwable. 885 * </p> 886 * 887 * <p> 888 * Unwraps: {@link InvocationTargetException}, {@link UndeclaredThrowableException}, {@link UncheckedIOException} 889 * and {@link UncheckedException} 890 * </p> 891 * 892 * @param throwable to be unwrapped 893 * @return the root cause, or original throwable if not unwrapped 894 * 895 * @since 0.2.0 896 * 897 */ 898 public static Throwable unwrap(Throwable throwable) 899 { 900 Throwable unwrapped = unwrapping(throwable); 901 if(unwrapped != throwable) { 902 unwrapped.addSuppressed(throwable); 903 } 904 return unwrapped; 905 } 906 907 908 private static Throwable unwrapping(Throwable throwable) 909 { 910 Set<Throwable> seen = new HashSet<>(); 911 while(isUnwrappable(throwable) && !seen.contains(throwable)) { 912 seen.add(throwable); 913 throwable = throwable.getCause(); 914 } 915 return throwable; 916 } 917 918 919 private static boolean isUnwrappable(Throwable throwable) 920 { 921 return throwable.getCause() != null 922 && (throwable instanceof InvocationTargetException 923 || throwable instanceof UndeclaredThrowableException 924 || throwable instanceof UncheckedIOException 925 || throwable instanceof UncheckedException); 926 } 927 928 929 /** 930 * <p> 931 * Recursively find the wrapped throwable 932 * </p> 933 * 934 * <b>NOTE</b>: this method now just delegates to {@link #unwrap(Throwable)} and is therefore superfluous, 935 * as such it will be removed in the next major release without impact to client code; given 936 * this, it is not marked {@link Deprecated} to avoid unnecessary upcasting to {@link Throwable}. 937 * 938 * @param throwable to be unwrapped 939 * @return the value of {@link UndeclaredThrowableException#getUndeclaredThrowable()} 940 * 941 * @since 0.2.0 942 * 943 * @see #unwrap(Throwable) 944 */ 945 public static Throwable unwrap(UndeclaredThrowableException throwable) 946 { 947 return unwrap((Throwable) throwable); 948 } 949 950 951 /** 952 * <p> 953 * Recursively find the wrapped throwable 954 * </p> 955 * 956 * <b>NOTE</b>: this method now just delegates to {@link #unwrap(Throwable)} and is therefore superfluous, 957 * as such it will be removed in the next major release without impact to client code; given 958 * this, it is not marked {@link Deprecated} to avoid unnecessary upcasting to {@link Throwable}. 959 * 960 * @param throwable to be unwrapped 961 * @return the value of {@link InvocationTargetException#getTargetException()} 962 * 963 * @since 0.2.0 964 */ 965 public static Throwable unwrap(InvocationTargetException throwable) 966 { 967 return unwrap((Throwable) throwable); 968 } 969 970 971 /** 972 * Invokes the {@link Iterable#forEach(Consumer)} method having unchecked the consumer 973 * 974 * @param <T> the consumed {@link Iterable}'s element type 975 * 976 * @param iterable the Iterable to consume each element of 977 * @param consumer the checked consumer of the Iterable's elements 978 * 979 * @since 0.4.0 980 * 981 * @see #uncheckConsumer(CheckedConsumer) 982 */ 983 public static <T> void forEach(Iterable<T> iterable, CheckedConsumer<T, ?> consumer) 984 { 985 iterable.forEach(uncheckConsumer(consumer)); 986 } 987 988 989 /** 990 * Invokes the {@link Map#forEach(BiConsumer)} method having unchecked the bi-consumer 991 * 992 * @param <K> the consumed {@link Map}'s key type 993 * @param <V> the consumed {@link Map}'s value type 994 * 995 * @param map the entries to consume 996 * @param consumer the consumer of the map's key value pairs 997 * 998 * @since 0.4.0 999 * 1000 * @see #uncheckBiConsumer(CheckedBiConsumer) 1001 */ 1002 public static <K, V> void forEach(Map<K, V> map, CheckedBiConsumer<K, V, ?> consumer) 1003 { 1004 map.forEach(uncheckBiConsumer(consumer)); 1005 } 1006 }