From 05aa6fb3237661a2a2dc794a1312d3ec866e5251 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 23 Jun 2018 22:29:47 +0100 Subject: [PATCH] Add Result.fromMaybe(Maybe, Supplier) --- src/main/java/net/kemitix/mon/maybe/Just.java | 3 +- .../java/net/kemitix/mon/maybe/Maybe.java | 54 +++++++++---------- .../java/net/kemitix/mon/maybe/Nothing.java | 5 +- .../java/net/kemitix/mon/result/Result.java | 36 ++++++++----- src/test/java/net/kemitix/mon/ResultTest.java | 49 +++++++++++++---- 5 files changed, 91 insertions(+), 56 deletions(-) diff --git a/src/main/java/net/kemitix/mon/maybe/Just.java b/src/main/java/net/kemitix/mon/maybe/Just.java index 0e480f0..449e523 100644 --- a/src/main/java/net/kemitix/mon/maybe/Just.java +++ b/src/main/java/net/kemitix/mon/maybe/Just.java @@ -36,7 +36,6 @@ import java.util.stream.Stream; * A Maybe where a value is present. * * @param the type of the content - * * @author Paul Campbell (pcampbell@kemitix.net) */ @RequiredArgsConstructor(access = AccessLevel.PROTECTED) @@ -45,7 +44,7 @@ final class Just implements Maybe { private final T value; @Override - public Maybe map(final Function f) { + public Maybe map(final Function f) { return new Just<>(f.apply(value)); } diff --git a/src/main/java/net/kemitix/mon/maybe/Maybe.java b/src/main/java/net/kemitix/mon/maybe/Maybe.java index c26ed13..51b4584 100644 --- a/src/main/java/net/kemitix/mon/maybe/Maybe.java +++ b/src/main/java/net/kemitix/mon/maybe/Maybe.java @@ -25,46 +25,21 @@ import lombok.NonNull; import net.kemitix.mon.Functor; import java.util.Optional; +import java.util.function.Function; /** * A value that may or may not be present. * * @param the type of the content of the Just - * * @author Paul Campbell (pcampbell@kemitix.net) */ public interface Maybe extends Functor>, MaybeStream, MaybeOptional { - /** - * Create a Maybe for the value that is present. - * - * @param value the value, not null - * @param the type of the value - * - * @return a Maybe of the value - */ - static Maybe just(@NonNull final T value) { - return new Just<>(value); - } - - /** - * Create a Maybe for a lack of a value. - * - * @param the type of the missing value - * - * @return an empty Maybe - */ - @SuppressWarnings("unchecked") - static Maybe nothing() { - return (Maybe) Nothing.INSTANCE; - } - /** * Create a Maybe for the value that may or may not be present. * * @param value the value, may be null * @param the type of the value - * * @return a Maybe, either a Just, or Nothing if value is null */ static Maybe maybe(final T value) { @@ -74,12 +49,33 @@ public interface Maybe extends Functor>, MaybeStream, MaybeOpt return just(value); } + /** + * Create a Maybe for a lack of a value. + * + * @param the type of the missing value + * @return an empty Maybe + */ + @SuppressWarnings("unchecked") + static Maybe nothing() { + return (Maybe) Nothing.INSTANCE; + } + + /** + * Create a Maybe for the value that is present. + * + * @param value the value, not null + * @param the type of the value + * @return a Maybe of the value + */ + static Maybe just(@NonNull final T value) { + return new Just<>(value); + } + /** * Create a Maybe from an {@link Optional}. * * @param optional the Optional * @param the type of the Optional - * * @return a Maybe * @deprecated need to find a better way of converting an Optional to a Maybe, but * without having to pass the Optional as a parameter @@ -88,7 +84,9 @@ public interface Maybe extends Functor>, MaybeStream, MaybeOpt @Deprecated static Maybe fromOptional(final Optional optional) { return optional.map(Maybe::maybe) - .orElse(nothing()); + .orElse(nothing()); } + @Override + Maybe map(Function f); } diff --git a/src/main/java/net/kemitix/mon/maybe/Nothing.java b/src/main/java/net/kemitix/mon/maybe/Nothing.java index 1ea6eb4..47448b0 100644 --- a/src/main/java/net/kemitix/mon/maybe/Nothing.java +++ b/src/main/java/net/kemitix/mon/maybe/Nothing.java @@ -32,7 +32,6 @@ import java.util.stream.Stream; * A Maybe where no value is present. * * @param the type of the missing content - * * @author Paul Campbell (pcampbell@kemitix.net) */ final class Nothing implements Maybe { @@ -40,8 +39,8 @@ final class Nothing implements Maybe { static final Maybe INSTANCE = new Nothing<>(); @Override - public Maybe map(final Function f) { - return this; + public Maybe map(final Function f) { + return (Maybe) INSTANCE; } @Override diff --git a/src/main/java/net/kemitix/mon/result/Result.java b/src/main/java/net/kemitix/mon/result/Result.java index 37775a9..e2d8c3d 100644 --- a/src/main/java/net/kemitix/mon/result/Result.java +++ b/src/main/java/net/kemitix/mon/result/Result.java @@ -26,38 +26,51 @@ import net.kemitix.mon.maybe.Maybe; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; /** * An Either type for holding a result or an error (exception). * * @param the type of the result when a success - * * @author Paul Campbell (pcampbell@kemitix.net) */ public interface Result { /** - * Create a Result for a success. + * Creates a Result from the Maybe, where the Result will be an error if the Maybe is Nothing. * - * @param value the value - * @param the type of the value - * @return a successful Result + * @param maybe the Maybe the might contain the value of the Result + * @param error the error that will be the Result if maybe is Nothing + * @param the type of the Maybe and the Result + * @return a Result containing the value of the Maybe when it is a Just, or the error when it is Nothing */ - static Result ok(final T value) { - return new Success<>(value); + static Result fromMaybe(final Maybe maybe, final Supplier error) { + return maybe.map(Result::ok) + .orElseGet(() -> Result.error(error.get())); } /** * Create a Result for an error. * * @param error the error (exception) - * @param the type had the result been a success + * @param the type had the result been a success * @return an error Result */ static Result error(final Throwable error) { return new Err<>(error); } + /** + * Create a Result for a success. + * + * @param value the value + * @param the type of the value + * @return a successful Result + */ + static Result ok(final T value) { + return new Success<>(value); + } + /** * Checks of the Result is an error. * @@ -77,7 +90,6 @@ public interface Result { * * @param f the mapping function the produces a Result * @param the type of the value withing the Result of the mapping function - * * @return a Result */ Result flatMap(Function> f); @@ -85,9 +97,8 @@ public interface Result { /** * Applies the functions to the value of a successful result, while doing nothing with an error. * - * @param f the mapping function to produce the new value + * @param f the mapping function to produce the new value * @param the type of the result of the mapping function - * * @return a Result */ Result map(Function f); @@ -96,7 +107,7 @@ public interface Result { * Matches the Result, either success or error, and supplies the appropriate Consumer with the value or error. * * @param onSuccess the Consumer to pass the value of a successful Result to - * @param onError the Consumer to pass the error from an error Result to + * @param onError the Consumer to pass the error from an error Result to */ void match(Consumer onSuccess, Consumer onError); @@ -107,4 +118,5 @@ public interface Result { * @return a Result containing a Maybe that may or may not contain a value */ Result> maybe(Predicate predicate); + } diff --git a/src/test/java/net/kemitix/mon/ResultTest.java b/src/test/java/net/kemitix/mon/ResultTest.java index 1bbb9e8..ef79954 100644 --- a/src/test/java/net/kemitix/mon/ResultTest.java +++ b/src/test/java/net/kemitix/mon/ResultTest.java @@ -6,8 +6,6 @@ import net.kemitix.mon.result.Result; import org.assertj.core.api.WithAssertions; import org.junit.Test; -import java.util.function.Predicate; - public class ResultTest implements WithAssertions { @Test @@ -195,6 +193,35 @@ public class ResultTest implements WithAssertions { ); } + @Test + public void justMaybe_isSuccess() { + //given + final Maybe just = Maybe.just(1); + //when + final Result result = Result.fromMaybe(just, () -> new RuntimeException()); + //then + assertThat(result.isOkay()).isTrue(); + result.match( + success -> assertThat(success).isEqualTo(1), + error -> fail("not an error") + ); + } + + @Test + public void nothingMaybe_isError() { + //given + final Maybe nothing = Maybe.nothing(); + final RuntimeException exception = new RuntimeException(); + //when + final Result result = Result.fromMaybe(nothing, () -> exception); + //then + assertThat(result.isError()).isTrue(); + result.match( + success -> fail("not a success"), + error -> assertThat(error).isSameAs(exception) + ); + } + @Test public void useCase_whenOkay_thenReturnSuccess() { //given @@ -265,20 +292,20 @@ public class ResultTest implements WithAssertions { calculateAverage(adjustedIntFromFile1, intFromFile2)))); } - private Result calculateAverage(final Integer val1, final Integer val2) { - return Result.ok((double) (val1 + val2) / 2); - } - - private Result adjustValue(Integer value) { - return Result.ok(value + 2); - } - - private Result readIntFromFile(String fileName) { + private Result readIntFromFile(final String fileName) { if (okay) { return Result.ok(fileName.length()); } return Result.error(new RuntimeException(fileName)); } + private Result adjustValue(final Integer value) { + return Result.ok(value + 2); + } + + private Result calculateAverage(final Integer val1, final Integer val2) { + return Result.ok((double) (val1 + val2) / 2); + } + } } \ No newline at end of file