Add Result.fromMaybe(Maybe, Supplier<Exception>)
This commit is contained in:
parent
62a61213cc
commit
05aa6fb323
5 changed files with 91 additions and 56 deletions
|
@ -36,7 +36,6 @@ import java.util.stream.Stream;
|
||||||
* A Maybe where a value is present.
|
* A Maybe where a value is present.
|
||||||
*
|
*
|
||||||
* @param <T> the type of the content
|
* @param <T> the type of the content
|
||||||
*
|
|
||||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
|
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
@ -45,7 +44,7 @@ final class Just<T> implements Maybe<T> {
|
||||||
private final T value;
|
private final T value;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <R> Maybe<?> map(final Function<T, R> f) {
|
public <R> Maybe<R> map(final Function<T, R> f) {
|
||||||
return new Just<>(f.apply(value));
|
return new Just<>(f.apply(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,46 +25,21 @@ import lombok.NonNull;
|
||||||
import net.kemitix.mon.Functor;
|
import net.kemitix.mon.Functor;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A value that may or may not be present.
|
* A value that may or may not be present.
|
||||||
*
|
*
|
||||||
* @param <T> the type of the content of the Just
|
* @param <T> the type of the content of the Just
|
||||||
*
|
|
||||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||||
*/
|
*/
|
||||||
public interface Maybe<T> extends Functor<T, Maybe<?>>, MaybeStream<T>, MaybeOptional<T> {
|
public interface Maybe<T> extends Functor<T, Maybe<?>>, MaybeStream<T>, MaybeOptional<T> {
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a Maybe for the value that is present.
|
|
||||||
*
|
|
||||||
* @param value the value, not null
|
|
||||||
* @param <T> the type of the value
|
|
||||||
*
|
|
||||||
* @return a Maybe of the value
|
|
||||||
*/
|
|
||||||
static <T> Maybe<T> just(@NonNull final T value) {
|
|
||||||
return new Just<>(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a Maybe for a lack of a value.
|
|
||||||
*
|
|
||||||
* @param <T> the type of the missing value
|
|
||||||
*
|
|
||||||
* @return an empty Maybe
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
static <T> Maybe<T> nothing() {
|
|
||||||
return (Maybe<T>) Nothing.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Maybe for the value that may or may not be present.
|
* Create a Maybe for the value that may or may not be present.
|
||||||
*
|
*
|
||||||
* @param value the value, may be null
|
* @param value the value, may be null
|
||||||
* @param <T> the type of the value
|
* @param <T> the type of the value
|
||||||
*
|
|
||||||
* @return a Maybe, either a Just, or Nothing if value is null
|
* @return a Maybe, either a Just, or Nothing if value is null
|
||||||
*/
|
*/
|
||||||
static <T> Maybe<T> maybe(final T value) {
|
static <T> Maybe<T> maybe(final T value) {
|
||||||
|
@ -74,12 +49,33 @@ public interface Maybe<T> extends Functor<T, Maybe<?>>, MaybeStream<T>, MaybeOpt
|
||||||
return just(value);
|
return just(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Maybe for a lack of a value.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the missing value
|
||||||
|
* @return an empty Maybe
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static <T> Maybe<T> nothing() {
|
||||||
|
return (Maybe<T>) Nothing.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Maybe for the value that is present.
|
||||||
|
*
|
||||||
|
* @param value the value, not null
|
||||||
|
* @param <T> the type of the value
|
||||||
|
* @return a Maybe of the value
|
||||||
|
*/
|
||||||
|
static <T> Maybe<T> just(@NonNull final T value) {
|
||||||
|
return new Just<>(value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Maybe from an {@link Optional}.
|
* Create a Maybe from an {@link Optional}.
|
||||||
*
|
*
|
||||||
* @param optional the Optional
|
* @param optional the Optional
|
||||||
* @param <T> the type of the Optional
|
* @param <T> the type of the Optional
|
||||||
*
|
|
||||||
* @return a Maybe
|
* @return a Maybe
|
||||||
* @deprecated need to find a better way of converting an Optional to a Maybe, but
|
* @deprecated need to find a better way of converting an Optional to a Maybe, but
|
||||||
* without having to pass the Optional as a parameter
|
* without having to pass the Optional as a parameter
|
||||||
|
@ -88,7 +84,9 @@ public interface Maybe<T> extends Functor<T, Maybe<?>>, MaybeStream<T>, MaybeOpt
|
||||||
@Deprecated
|
@Deprecated
|
||||||
static <T> Maybe<T> fromOptional(final Optional<T> optional) {
|
static <T> Maybe<T> fromOptional(final Optional<T> optional) {
|
||||||
return optional.map(Maybe::maybe)
|
return optional.map(Maybe::maybe)
|
||||||
.orElse(nothing());
|
.orElse(nothing());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
<R> Maybe<R> map(Function<T, R> f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ import java.util.stream.Stream;
|
||||||
* A Maybe where no value is present.
|
* A Maybe where no value is present.
|
||||||
*
|
*
|
||||||
* @param <T> the type of the missing content
|
* @param <T> the type of the missing content
|
||||||
*
|
|
||||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||||
*/
|
*/
|
||||||
final class Nothing<T> implements Maybe<T> {
|
final class Nothing<T> implements Maybe<T> {
|
||||||
|
@ -40,8 +39,8 @@ final class Nothing<T> implements Maybe<T> {
|
||||||
static final Maybe<?> INSTANCE = new Nothing<>();
|
static final Maybe<?> INSTANCE = new Nothing<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <R> Maybe<?> map(final Function<T, R> f) {
|
public <R> Maybe<R> map(final Function<T, R> f) {
|
||||||
return this;
|
return (Maybe<R>) INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,38 +26,51 @@ import net.kemitix.mon.maybe.Maybe;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Either type for holding a result or an error (exception).
|
* An Either type for holding a result or an error (exception).
|
||||||
*
|
*
|
||||||
* @param <T> the type of the result when a success
|
* @param <T> the type of the result when a success
|
||||||
*
|
|
||||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||||
*/
|
*/
|
||||||
public interface Result<T> {
|
public interface Result<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 maybe the Maybe the might contain the value of the Result
|
||||||
* @param <T> the type of the value
|
* @param error the error that will be the Result if maybe is Nothing
|
||||||
* @return a successful Result
|
* @param <T> 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 <T> Result<T> ok(final T value) {
|
static <T> Result<T> fromMaybe(final Maybe<T> maybe, final Supplier<Exception> error) {
|
||||||
return new Success<>(value);
|
return maybe.map(Result::ok)
|
||||||
|
.orElseGet(() -> Result.error(error.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Result for an error.
|
* Create a Result for an error.
|
||||||
*
|
*
|
||||||
* @param error the error (exception)
|
* @param error the error (exception)
|
||||||
* @param <T> the type had the result been a success
|
* @param <T> the type had the result been a success
|
||||||
* @return an error Result
|
* @return an error Result
|
||||||
*/
|
*/
|
||||||
static <T> Result<T> error(final Throwable error) {
|
static <T> Result<T> error(final Throwable error) {
|
||||||
return new Err<>(error);
|
return new Err<>(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Result for a success.
|
||||||
|
*
|
||||||
|
* @param value the value
|
||||||
|
* @param <T> the type of the value
|
||||||
|
* @return a successful Result
|
||||||
|
*/
|
||||||
|
static <T> Result<T> ok(final T value) {
|
||||||
|
return new Success<>(value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks of the Result is an error.
|
* Checks of the Result is an error.
|
||||||
*
|
*
|
||||||
|
@ -77,7 +90,6 @@ public interface Result<T> {
|
||||||
*
|
*
|
||||||
* @param f the mapping function the produces a Result
|
* @param f the mapping function the produces a Result
|
||||||
* @param <R> the type of the value withing the Result of the mapping function
|
* @param <R> the type of the value withing the Result of the mapping function
|
||||||
*
|
|
||||||
* @return a Result
|
* @return a Result
|
||||||
*/
|
*/
|
||||||
<R> Result<R> flatMap(Function<T, Result<R>> f);
|
<R> Result<R> flatMap(Function<T, Result<R>> f);
|
||||||
|
@ -85,9 +97,8 @@ public interface Result<T> {
|
||||||
/**
|
/**
|
||||||
* Applies the functions to the value of a successful result, while doing nothing with an error.
|
* 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 <R> the type of the result of the mapping function
|
* @param <R> the type of the result of the mapping function
|
||||||
*
|
|
||||||
* @return a Result
|
* @return a Result
|
||||||
*/
|
*/
|
||||||
<R> Result<R> map(Function<T, R> f);
|
<R> Result<R> map(Function<T, R> f);
|
||||||
|
@ -96,7 +107,7 @@ public interface Result<T> {
|
||||||
* Matches the Result, either success or error, and supplies the appropriate Consumer with the value or error.
|
* 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 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<T> onSuccess, Consumer<Throwable> onError);
|
void match(Consumer<T> onSuccess, Consumer<Throwable> onError);
|
||||||
|
|
||||||
|
@ -107,4 +118,5 @@ public interface Result<T> {
|
||||||
* @return a Result containing a Maybe that may or may not contain a value
|
* @return a Result containing a Maybe that may or may not contain a value
|
||||||
*/
|
*/
|
||||||
Result<Maybe<T>> maybe(Predicate<T> predicate);
|
Result<Maybe<T>> maybe(Predicate<T> predicate);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,6 @@ import net.kemitix.mon.result.Result;
|
||||||
import org.assertj.core.api.WithAssertions;
|
import org.assertj.core.api.WithAssertions;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
public class ResultTest implements WithAssertions {
|
public class ResultTest implements WithAssertions {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -195,6 +193,35 @@ public class ResultTest implements WithAssertions {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void justMaybe_isSuccess() {
|
||||||
|
//given
|
||||||
|
final Maybe<Integer> just = Maybe.just(1);
|
||||||
|
//when
|
||||||
|
final Result<Integer> 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<Object> nothing = Maybe.nothing();
|
||||||
|
final RuntimeException exception = new RuntimeException();
|
||||||
|
//when
|
||||||
|
final Result<Object> result = Result.fromMaybe(nothing, () -> exception);
|
||||||
|
//then
|
||||||
|
assertThat(result.isError()).isTrue();
|
||||||
|
result.match(
|
||||||
|
success -> fail("not a success"),
|
||||||
|
error -> assertThat(error).isSameAs(exception)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void useCase_whenOkay_thenReturnSuccess() {
|
public void useCase_whenOkay_thenReturnSuccess() {
|
||||||
//given
|
//given
|
||||||
|
@ -265,20 +292,20 @@ public class ResultTest implements WithAssertions {
|
||||||
calculateAverage(adjustedIntFromFile1, intFromFile2))));
|
calculateAverage(adjustedIntFromFile1, intFromFile2))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result<Double> calculateAverage(final Integer val1, final Integer val2) {
|
private Result<Integer> readIntFromFile(final String fileName) {
|
||||||
return Result.ok((double) (val1 + val2) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Result<Integer> adjustValue(Integer value) {
|
|
||||||
return Result.ok(value + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Result<Integer> readIntFromFile(String fileName) {
|
|
||||||
if (okay) {
|
if (okay) {
|
||||||
return Result.ok(fileName.length());
|
return Result.ok(fileName.length());
|
||||||
}
|
}
|
||||||
return Result.error(new RuntimeException(fileName));
|
return Result.error(new RuntimeException(fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Result<Integer> adjustValue(final Integer value) {
|
||||||
|
return Result.ok(value + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result<Double> calculateAverage(final Integer val1, final Integer val2) {
|
||||||
|
return Result.ok((double) (val1 + val2) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue