[result] add orElseThrow(Class) and orElseThrowUnchecked()

Split `MonResultException` into `ErrorResultException` and `UnexpectedErrorResultException`.
This commit is contained in:
Paul Campbell 2018-10-04 07:24:50 +01:00
parent c0ee1cdbc7
commit 48e19fb653
6 changed files with 152 additions and 12 deletions

View file

@ -73,8 +73,22 @@ class Err<T> implements Result<T> {
}
@Override
public T orElseThrow() throws MonResultException {
throw MonResultException.with(error);
public T orElseThrow() throws Throwable {
throw error;
}
@Override
@SuppressWarnings("unchecked")
public <E extends Exception> T orElseThrow(final Class<E> type) throws E {
if (type.isInstance(error)) {
throw (E) error;
}
throw UnexpectedErrorResultException.with(error);
}
@Override
public T orElseThrowUnchecked() {
throw ErrorResultException.with(error);
}
@Override

View file

@ -22,13 +22,15 @@
package net.kemitix.mon.result;
/**
* An Unchecked wrapper for exceptions thrown within a {@code Result}.
* An unchecked wrapper fot exceptions thrown within a {@link Result}.
*
* <p>Used by {@link Result#orElseThrowUnchecked()} when the {@link Result} is an error.</p>
*
* @author Paul Campbell (pcampbell@kemitix.net)
*/
public final class MonResultException extends RuntimeException {
public final class ErrorResultException extends RuntimeException {
private MonResultException(final Throwable cause) {
private ErrorResultException(final Throwable cause) {
super(cause);
}
@ -36,9 +38,9 @@ public final class MonResultException extends RuntimeException {
* Creates a new object.
*
* @param cause the cause
* @return a MonResultException contain the cause
* @return a {@link ErrorResultException} containing the cause
*/
static MonResultException with(final Throwable cause) {
return new MonResultException(cause);
static ErrorResultException with(final Throwable cause) {
return new ErrorResultException(cause);
}
}

View file

@ -99,7 +99,7 @@ public interface Result<T> extends Functor<T, Result<?>> {
@SuppressWarnings("illegalcatch")
public static <T> Maybe<T> toMaybe(final Result<T> result) {
try {
return Maybe.just(result.orElseThrow());
return Maybe.just(result.orElseThrow(Exception.class));
} catch (final Throwable throwable) {
return Maybe.nothing();
}
@ -109,9 +109,28 @@ public interface Result<T> extends Functor<T, Result<?>> {
* Extracts the successful value from the result, or throws the error Throwable.
*
* @return the value if a success
* @throws MonResultException if the result is an error
* @throws Throwable if the result is an error
*/
public abstract T orElseThrow() throws MonResultException;
@SuppressWarnings("illegalthrows")
public abstract T orElseThrow() throws Throwable;
/**
* Extracts the successful value from the result, or throws the error Throwable.
*
* @param type the type of checked exception that may be thrown
* @param <E> the type of the checked exception to throw
*
* @return the value if a success
* @throws E if the result is an error
*/
public abstract <E extends Exception> T orElseThrow(Class<E> type) throws E;
/**
* Extracts the successful value from the result, or throws the error in a {@link UnexpectedErrorResultException}.
*
* @return the value if a success
*/
public abstract T orElseThrowUnchecked();
/**
* Swaps the inner Result of a Maybe, so that a Result is on the outside.

View file

@ -75,6 +75,16 @@ class Success<T> implements Result<T> {
return value;
}
@Override
public <E extends Exception> T orElseThrow(final Class<E> type) throws E {
return value;
}
@Override
public T orElseThrowUnchecked() {
return value;
}
@Override
public Result<T> peek(final Consumer<T> consumer) {
consumer.accept(value);

View file

@ -0,0 +1,47 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2018 Paul Campbell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package net.kemitix.mon.result;
/**
* An Unchecked wrapper for unexpected exceptions thrown within a {@link Result}.
*
* <p>Used by {@link Result#orElseThrow(Class)} when the {@link Result} is an error of a different type to the
* parameter.</p>
*
* @author Paul Campbell (pcampbell@kemitix.net)
*/
public final class UnexpectedErrorResultException extends RuntimeException {
private UnexpectedErrorResultException(final Throwable cause) {
super(cause);
}
/**
* Creates a new object.
*
* @param cause the cause
* @return a {@link UnexpectedErrorResultException} containing the cause
*/
static UnexpectedErrorResultException with(final Throwable cause) {
return new UnexpectedErrorResultException(cause);
}
}

View file

@ -2,6 +2,8 @@ package net.kemitix.mon;
import lombok.RequiredArgsConstructor;
import net.kemitix.mon.maybe.Maybe;
import net.kemitix.mon.result.ErrorResultException;
import net.kemitix.mon.result.UnexpectedErrorResultException;
import net.kemitix.mon.result.Result;
import org.assertj.core.api.WithAssertions;
import org.junit.Test;
@ -292,7 +294,53 @@ public class ResultTest implements WithAssertions {
final RuntimeException exception = new RuntimeException();
final Result<Integer> error = Result.error(exception);
//when
assertThatThrownBy(() -> error.orElseThrow()).hasCause(exception);
assertThatThrownBy(() -> error.orElseThrow()).isSameAs(exception);
}
@Test public void okay_whenOrElseThrowT_isValue() throws Exception {
//given
final Result<Integer> ok = Result.ok(1);
//when
final Integer value = ok.orElseThrow(Exception.class);
//then
assumeThat(value).isEqualTo(1);
}
@Test public void errorT_whenOrElseThrowT_throwsT() {
//given
final RuntimeException exception = new RuntimeException();
final Result<Object> error = Result.error(exception);
//then
assertThatThrownBy(() -> error.orElseThrow(RuntimeException.class)).isSameAs(exception);
}
@Test public void errorR_whenOrElseThrowT_throwsWrappedR() {
//given
final IOException exception = new IOException();
final Result<Object> error = Result.error(exception);
//then
assertThatThrownBy(() -> error.orElseThrow(RuntimeException.class))
.isInstanceOf(UnexpectedErrorResultException.class)
.hasCause(exception);
}
@Test public void okay_whenOrElseThrowUnchecked_isValue() {
//given
final Result<Integer> ok = Result.ok(1);
//when
final Integer value = ok.orElseThrowUnchecked();
//then
assumeThat(value).isEqualTo(1);
}
@Test public void error_whenOrElseThrowUnchecked_throwsWrapped() {
//given
final IOException exception = new IOException();
final Result<Object> error = Result.error(exception);
//then
assertThatThrownBy(() -> error.orElseThrowUnchecked())
.isInstanceOf(ErrorResultException.class)
.hasCause(exception);
}
@Test