From 7201261bad70189ac7c5d2ae0fa9e3c49867729f Mon Sep 17 00:00:00 2001 From: 2bllw8 <2bllw8@gmail.com> Date: Sat, 19 Feb 2022 21:17:52 +0100 Subject: [PATCH] Add CheckedSupplier to replace CheckedException --- README.md | 14 ++----- .../exe/bbllw8/either/CheckedException.java | 8 ++-- .../exe/bbllw8/either/CheckedSupplier.java | 18 +++++++++ .../main/java/exe/bbllw8/either/Failure.java | 14 +++++++ lib/src/main/java/exe/bbllw8/either/Try.java | 40 +++++-------------- .../java/exe/bbllw8/either/FailureTest.java | 30 ++++++++++++++ .../java/exe/bbllw8/either/SuccessTest.java | 2 +- .../test/java/exe/bbllw8/either/TryTest.java | 2 +- 8 files changed, 83 insertions(+), 45 deletions(-) create mode 100644 lib/src/main/java/exe/bbllw8/either/CheckedSupplier.java diff --git a/README.md b/README.md index 736816a..a970735 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,7 @@ implementation 'io.github.2bllw8:either:3.1.0' ## Usage ```java -import exe.bbllw8.either.CheckedException; import exe.bbllw8.either.Try; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; @@ -45,14 +43,10 @@ import java.util.stream.Collectors; public class Main { public static void main(String[] args) { - Arrays.stream(args).map((String arg) -> Try.from(() -> { - try { - return Files.lines(Paths.get(arg)) - .collect(Collectors.joining("\n")); - } catch (IOException e) { - throw new CheckedException(e); - } - }).filter(text -> text.length() > 2) + Arrays.stream(args).map((String arg) -> Try.from(() -> + Files.lines(Paths.get(arg)) + .collect(Collectors.joining("\n"))) + .filter(text -> text.length() > 2) .map(text -> text.substring(2)) .flatMap(text -> Try.from(() -> Integer.parseInt(text))) .toEither() diff --git a/lib/src/main/java/exe/bbllw8/either/CheckedException.java b/lib/src/main/java/exe/bbllw8/either/CheckedException.java index 6790617..2a0a602 100644 --- a/lib/src/main/java/exe/bbllw8/either/CheckedException.java +++ b/lib/src/main/java/exe/bbllw8/either/CheckedException.java @@ -4,11 +4,9 @@ */ package exe.bbllw8.either; -import java.util.function.Supplier; - /** * A CheckedException instance is used to catch checked Exceptions for usage in {@link - * Try#from(Supplier)}. + * Try#from(CheckedSupplier)}. * *
  * public class Example {
@@ -25,9 +23,11 @@
  * 
* * @author 2bllw8 - * @see Try#from(Supplier) + * @see Try#from(CheckedSupplier) * @since 2.2.0 + * @deprecated Use {@link CheckedSupplier} instead of thowing wrapped exceptions. */ +@Deprecated public final class CheckedException extends RuntimeException { private static final long serialVersionUID = 2896775411630760282L; diff --git a/lib/src/main/java/exe/bbllw8/either/CheckedSupplier.java b/lib/src/main/java/exe/bbllw8/either/CheckedSupplier.java new file mode 100644 index 0000000..7f061c6 --- /dev/null +++ b/lib/src/main/java/exe/bbllw8/either/CheckedSupplier.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2022 2bllw8 + * SPDX-License-Identifier: Apache-2.0 + */ +package exe.bbllw8.either; + +/** + * Represents a supplier of results that may throw a {@link Throwable}. + * + * @param The type of result supplied by this supplier + * @author 2bllw8 + * @since 3.2.0 + */ +@FunctionalInterface +public interface CheckedSupplier { + + T get() throws Throwable; +} diff --git a/lib/src/main/java/exe/bbllw8/either/Failure.java b/lib/src/main/java/exe/bbllw8/either/Failure.java index 12deec5..d3f9fa0 100644 --- a/lib/src/main/java/exe/bbllw8/either/Failure.java +++ b/lib/src/main/java/exe/bbllw8/either/Failure.java @@ -21,6 +21,7 @@ public final class Failure extends Try { private transient final Throwable throwable; public Failure(Throwable throwable) { + assertNotFatal(throwable); this.throwable = throwable; } @@ -140,4 +141,17 @@ public int hashCode() { public String toString() { return "Failure(" + throwable + ')'; } + + /** + * Assert that the given throwable is not fatal. + */ + private static void assertNotFatal(Throwable t) { + if (t instanceof VirtualMachineError) { + throw (VirtualMachineError) t; + } else if (t instanceof ThreadDeath) { + throw (ThreadDeath) t; + } else if (t instanceof LinkageError) { + throw (LinkageError) t; + } + } } diff --git a/lib/src/main/java/exe/bbllw8/either/Try.java b/lib/src/main/java/exe/bbllw8/either/Try.java index b60cf8b..5e1b23e 100644 --- a/lib/src/main/java/exe/bbllw8/either/Try.java +++ b/lib/src/main/java/exe/bbllw8/either/Try.java @@ -7,7 +7,6 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.Supplier; /** * The {@link Try} type represents a computation that may either result in an exception, or return a @@ -40,7 +39,7 @@ public abstract class Try { *
    *
  • {@link Success}
  • *
  • {@link Failure}
  • - *
  • {@link Try#from(Supplier)}
  • + *
  • {@link Try#from(CheckedSupplier)}
  • *
* * @hidden @@ -205,36 +204,19 @@ public static Try flatten(Try> tryTry) { * * @since 3.0.0 */ - @SuppressWarnings({"PMD.AvoidCatchingThrowable"}) - public static Try from(Supplier supplier) { + @SuppressWarnings({ + "deprecation", + "PMD.AvoidCatchingThrowable", + }) + public static Try from(CheckedSupplier supplier) { + //noinspection deprecation try { return new Success<>(supplier.get()); - } catch (CheckedException e) { - // Wrapped checked exception - final Throwable t = e.getCause(); - if (isFatal(t)) { - // Fatal - throw e; - } else { - return new Failure<>(t); - } + } catch (CheckedException t) { + // TODO: remove this clause when CheckedException is removed + return new Failure<>(t.getCause()); } catch (Throwable t) { - if (isFatal(t)) { - // Fatal - throw t; - } else { - return new Failure<>(t); - } + return new Failure<>(t); } } - - /** - * @return Returns whether the given throwable is fatal. - */ - private static boolean isFatal(Throwable t) { - return t instanceof VirtualMachineError - || t instanceof ThreadDeath - || t instanceof InterruptedException - || t instanceof LinkageError; - } } diff --git a/lib/src/test/java/exe/bbllw8/either/FailureTest.java b/lib/src/test/java/exe/bbllw8/either/FailureTest.java index e18187a..cdda861 100644 --- a/lib/src/test/java/exe/bbllw8/either/FailureTest.java +++ b/lib/src/test/java/exe/bbllw8/either/FailureTest.java @@ -187,4 +187,34 @@ public void stringRepresentation() { throw new IllegalStateException("something"); }).toString()); } + + @Test + public void multipleThrow() { + Assert.assertTrue("Multiple thrown classes are handled (throwable #1)", + Try.from(() -> new IntToBoolean().convert(2)) + .recover(t -> t instanceof IllegalAccessException) + .get()); + Assert.assertTrue("Multiple thrown classes are handled (throwable #2)", + Try.from(() -> new IntToBoolean().convert(3)) + .recover(t -> t instanceof IllegalArgumentException) + .get()); + } + + private static class IntToBoolean { + + boolean convert(int result) throws IllegalAccessException, IllegalArgumentException { + switch (result) { + case 0: + return false; + case 1: + return true; + case 2: + // You have no authority to discover the dark truth about + // the third hidden boolean value + throw new IllegalAccessException(); + default: + throw new IllegalArgumentException(); + } + } + } } diff --git a/lib/src/test/java/exe/bbllw8/either/SuccessTest.java b/lib/src/test/java/exe/bbllw8/either/SuccessTest.java index c8c961b..da5bee8 100644 --- a/lib/src/test/java/exe/bbllw8/either/SuccessTest.java +++ b/lib/src/test/java/exe/bbllw8/either/SuccessTest.java @@ -108,7 +108,7 @@ public void transform() { new Success<>(12), Try.from(() -> "12").transform(value -> Try.from(() -> Integer.parseInt(value)), t -> Try.from(() -> { - throw new CheckedException(t); + throw t; }))); } diff --git a/lib/src/test/java/exe/bbllw8/either/TryTest.java b/lib/src/test/java/exe/bbllw8/either/TryTest.java index 01f2044..772c108 100644 --- a/lib/src/test/java/exe/bbllw8/either/TryTest.java +++ b/lib/src/test/java/exe/bbllw8/either/TryTest.java @@ -28,7 +28,7 @@ public void flatten() { public void from() { Assert.assertTrue("A supplier throwing an exception should return a failure", Try.from(() -> { - throw new CheckedException(new Throwable()); + throw new Throwable(); }).isFailure()); Assert.assertTrue("A supplier throwing an exception should return a failure", Try.from(() -> Integer.parseInt("-")).isFailure());