From a7352711e1d6c36b16235c042e139946ad6fb35c Mon Sep 17 00:00:00 2001 From: Ben Culkin Date: Fri, 26 Feb 2021 16:15:54 -0500 Subject: Update --- src/main/java/bjc/data/Option.java | 19 +++-- src/main/java/bjc/functypes/ThrowFunction.java | 97 +++++++++++++++++--------- src/test/java/bjc/data/EitherTest.java | 40 +++++++---- 3 files changed, 104 insertions(+), 52 deletions(-) diff --git a/src/main/java/bjc/data/Option.java b/src/main/java/bjc/data/Option.java index 6c76d59..6ca8b13 100644 --- a/src/main/java/bjc/data/Option.java +++ b/src/main/java/bjc/data/Option.java @@ -13,7 +13,15 @@ import java.util.function.UnaryOperator; */ public class Option implements Holder { private ContainedType held; - + private boolean isHolding; + + /** + * Create a new empty optional. + */ + public Option() { + isHolding = false; + } + /** * Create a new optional, using the given initial value. * @@ -22,12 +30,13 @@ public class Option implements Holder { */ public Option(final ContainedType seed) { held = seed; + isHolding = true; } @Override public Holder bind(final Function> binder) { - if (held == null) return new Option<>(null); + if (isHolding) return new Option<>(); return binder.apply(held); } @@ -41,7 +50,7 @@ public class Option implements Holder { @Override public Holder map(final Function mapper) { - if (held == null) return new Option<>(null); + if (isHolding) return new Option<>(); return new Option<>(mapper.apply(held)); } @@ -49,7 +58,7 @@ public class Option implements Holder { @Override public Holder transform(final UnaryOperator transformer) { - if (held != null) held = transformer.apply(held); + if (isHolding) held = transformer.apply(held); return this; } @@ -57,7 +66,7 @@ public class Option implements Holder { @Override public UnwrappedType unwrap(final Function unwrapper) { - if (held == null) return null; + if (isHolding) return null; return unwrapper.apply(held); } diff --git a/src/main/java/bjc/functypes/ThrowFunction.java b/src/main/java/bjc/functypes/ThrowFunction.java index 132f55c..3714cad 100644 --- a/src/main/java/bjc/functypes/ThrowFunction.java +++ b/src/main/java/bjc/functypes/ThrowFunction.java @@ -1,5 +1,6 @@ package bjc.functypes; +import java.util.*; import java.util.function.*; /** @@ -24,6 +25,46 @@ public interface ThrowFunction */ public ReturnType apply(InputType arg) throws ExType; + /** + * Converts this into a {@link Function} by handling any thrown exceptions, + * then mapping the return type to get a consistent return type. + * + * @param The new return type. + * + * @param clasz The class of the handled exception. This needs to be provided + * because you can't catch a generic exception, and we want to + * make sure that we aren't catching any types of exception that + * we aren't supposed to. + * @param mapper The function which maps the normal return. + * @param handler The handler to use. + * + * @return A function which will either return its proper value, or the result + * of invoking the handler. + */ + @SuppressWarnings("unchecked") + default Function swallowMap( + Class clasz, + Function mapper, + Function handler) + { + return (inp) -> { + try { + return mapper.apply(this.apply(inp)); + } catch (Throwable ex) { + if (clasz.isInstance(ex)) { + // Swallow this + return handler.apply((ExType) ex); + } else { + String msg = "Exception of incorrect type to be handled, only " + + clasz.getName() + + " are handled"; + + throw new RuntimeException(msg, ex); + } + } + }; + } + /** * Converts this into a {@link Function} by handling any thrown exceptions. * @@ -37,30 +78,10 @@ public interface ThrowFunction * @return A function which will either return its proper value, or the result * of invoking the handler. */ - @SuppressWarnings("unchecked") default Function swallow( Class clasz, Function handler) { - return (inp) -> - { - try - { - return this.apply(inp); - } catch (Throwable ex) { - if (clasz.isInstance(ex)) - { - // Swallow this - return handler.apply((ExType) ex); - } else - { - String msg = "Exception of incorrect type to be handled, only " - + clasz.getName() - + " are handled"; - - throw new RuntimeException(msg, ex); - } - } - }; + return swallowMap(clasz, (arg) -> arg, handler); } /** @@ -73,20 +94,16 @@ public interface ThrowFunction */ @SuppressWarnings("unchecked") default Function recover( - Class clasz, BiFunction rescue) { - return Fixpoints.fix((arg, self) -> - { - try - { + Class clasz, BiFunction rescue) + { + return Fixpoints.fix((arg, self) -> { + try { return this.apply(arg); - } catch (Throwable ex) - { - if (clasz.isInstance(ex)) - { + } catch (Throwable ex) { + if (clasz.isInstance(ex)) { // Swallow this return self.apply(rescue.apply(arg, (ExType) ex)); - } else - { + } else { String msg = "Exception of incorrect type to be handled, only " + clasz.getName() + " are handled"; @@ -125,6 +142,22 @@ public interface ThrowFunction return (arg) -> func.apply(this.apply(arg)); } + /** Convert this function into one which will return an empty optional if an + * exception is thrown, returning an optional containing the value otherwise. + * + * Note that if this function returns a null value by itself, that will also + * yield an empty nullable. + * + * @param clasz The class of the exception. Needed because of type erasure, + * to ensure that we are catching the proper class. + * + * @return A function which returns an optional instead. + */ + default Function> + makeTotal(Class clasz) + { + return swallowMap(clasz, Optional::ofNullable, (ignored) -> Optional.empty()); + } /** * ThrowFunctions and functions which return a {@link Thrower} are isomorphic. * diff --git a/src/test/java/bjc/data/EitherTest.java b/src/test/java/bjc/data/EitherTest.java index bbf94b7..ef2d12b 100644 --- a/src/test/java/bjc/data/EitherTest.java +++ b/src/test/java/bjc/data/EitherTest.java @@ -2,24 +2,34 @@ package bjc.data; import static org.junit.Assert.*; -import org.junit.Test; +import java.util.*; -/** - * Test Either - * @author Ben Culkin - * - */ -public class EitherTest { +import org.junit.*; - /** - * Do a test of Either. - */ +@SuppressWarnings("javadoc") +public class EitherTest +{ + private Either leftEither; + private Either rightEither; + + @Before + public void setUp() throws Exception { + leftEither = Either.left("left"); + rightEither = Either.right("right"); + } + + @Test + public void testIsLeft() { + assertTrue("isLeft properly marks left eithers", leftEither.isLeft()); + assertFalse("isLeft properly marks right eithers", rightEither.isLeft()); + } + @Test - public void test() { - Either left = Either.left("left"); - Either right = Either.right("right"); - - assertNotEquals(left, right); + public void testGetLeft() { + assertEquals("getLeft treats left eithers properly", + Optional.of("left"), leftEither.getLeft()); + assertEquals("getLeft treats right eithers properly", + Optional.empty(), rightEither.getLeft()); } } -- cgit v1.2.3