Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement recoverAndTry and recoverAllAndTry #2948

Open
wants to merge 3 commits into
base: version/1.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/main/java/io/vavr/control/Try.java
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,62 @@ public final Try<T> recoverWith(Function<? super Throwable, ? extends Try<? exte
}
}

/**
* Returns {@code this}, if this is a {@link Try.Success}, otherwise attempts to recover from any failure
* by evaluating the given {@code recoveryAttempt} (via {@link Try#of(CheckedFunction0)}).
*
* <pre>{@code
* // = Success(5)
* Try.of(() -> 5)
* .recoverAllAndTry(() -> 10);
*
* // = Success(10)
* Try.of(() -> 1/0)
* .recoverAllAndTry(() -> 10);
* }</pre>
*
* @param recoveryAttempt A checked function that provides a fallback in case of a failure
* @return a {@code Try} that is either this {@code Success} or a new {@code Try} evaluated from {@code recoveryAttempt}
* @throws NullPointerException if {@code recoveryAttempt} is null
*/
public final Try<T> recoverAllAndTry(CheckedFunction0<? extends T> recoveryAttempt) {
Objects.requireNonNull(recoveryAttempt, "recoveryAttempt is null");
return isFailure() ? of(recoveryAttempt) : this;
}

/**
* Returns {@code this}, if this is a {@link Try.Success}, otherwise attempts to recover from failure when the
* underlying cause is assignable to the specified {@code exceptionType}, by evaluating the given
* {@code recoveryAttempt} (via {@link Try#of(CheckedFunction0)}).
*
* <pre>{@code
* // = Success(5)
* Try.of(() -> 5)
* .recoverAndTry(ArithmeticException.class, () -> 10);
*
* // = Success(10)
* Try.of(() -> 1/0)
* .recoverAndTry(ArithmeticException.class, () -> 10);
*
* // = Failure(java.lang.ArithmeticException: / by zero)
* Try.of(() -> 1/0)
* .recoverAndTry(NullPointerException.class, () -> 10);
* }</pre>
*
* @param <X> The type of the exception that may be recovered
* @param exceptionType The specific exception type that should trigger the recovery
* @param recoveryAttempt A checked function that provides a fallback in case of a matching failure
* @return a {@code Try} that is either this {@code Success}, or a new {@code Try} evaluated from {@code recoveryAttempt}
* @throws NullPointerException if {@code exceptionType} or {@code recoveryAttempt} is null
*/
public final <X extends Throwable> Try<T> recoverAndTry(Class<X> exceptionType, CheckedFunction0<? extends T> recoveryAttempt) {
Objects.requireNonNull(exceptionType, "exceptionType is null");
Objects.requireNonNull(recoveryAttempt, "recoveryAttempt is null");
return isFailure() && exceptionType.isAssignableFrom(getCause().getClass())
? of(recoveryAttempt)
: this;
}

/**
* Converts this {@code Try} to an {@link Either}.
*
Expand Down
59 changes: 59 additions & 0 deletions src/test/java/io/vavr/control/TryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,65 @@ public void shouldNotRecoverFailureWhenExceptionTypeIsntAssignable(){
assertThat(Try.of(() -> { throw error; }).recoverWith(Error.class, success()).getCause()).isSameAs(error);
}

// -- recoverAllAndTry

@Test
public void shouldRecoverFailure() {
assertThat(failure()
.recoverAllAndTry(() -> OK))
.isEqualTo(Try.success(OK));
}

@Test
public void shouldNotRecoverSuccess() {
final String initialValue = "INITIAL";
final String attemptValue = "RECOVERY";
assertThat(Try.success(initialValue)
.recoverAllAndTry(() -> attemptValue))
.isEqualTo(Try.success(initialValue));
}

@Test
public void shouldThrowNullPointerExceptionWhenRecoveryAttemptIsNull() {
assertThrows(NullPointerException.class, () -> failure().recoverAllAndTry(null));
}

// -- recoverAndTry

@Test
public void shouldRecoverCorrectTypeOfFailure() {
assertThat(Try.failure(new RuntimeException())
.recoverAndTry(RuntimeException.class, () -> OK))
.isEqualTo(Try.success(OK));
}

@Test
public void shouldNotRecoverIncorrectTypeOfFailure() {
Try<Object> initialFailure = Try.failure(new RuntimeException());
assertThat(initialFailure
.recoverAndTry(IllegalStateException.class, () -> OK))
.isEqualTo(initialFailure);
}

@Test
public void shouldNotRecoverSuccessForRecoverAndTry() {
final String initialValue = "INITIAL";
final String attemptValue = "RECOVERY";
assertThat(Try.success(initialValue)
.recoverAndTry(Throwable.class, () -> attemptValue))
.isEqualTo(Try.success(initialValue));
}

@Test
public void shouldThrowNullPointerExceptionWhenExceptionTypeIsNull() {
assertThrows(NullPointerException.class, () -> failure().recoverAndTry(null, () -> OK));
}

@Test
public void shouldThrowNullPointerExceptionWhenRecoveryAttemptIsNullForRecoverAndTry() {
assertThrows(NullPointerException.class, () -> failure().recoverAndTry(Throwable.class, null));
}

// -- onFailure

@Test
Expand Down