Skip to content

Commit da85b37

Browse files
authored
Adding Future.recover(Class<X> exceptionType, Function) (#2671)
1 parent eaa5042 commit da85b37

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

src/main/java/io/vavr/concurrent/Future.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,30 @@ default Future<T> recover(Function<? super Throwable, ? extends T> f) {
10781078
return transformValue(t -> t.recover(f));
10791079
}
10801080

1081+
/**
1082+
* Handles a failure of this Future by returning another result.
1083+
* <p>
1084+
* Returns this, if this is a Success or this is a Failure and the cause is not assignable from {@code exceptionType}.
1085+
* Otherwise tries to recover the exception of the failure with {@code f}.
1086+
* <p>
1087+
* Example:
1088+
* <pre><code>
1089+
* // = "oh!"
1090+
* Future.of(() -&gt; new Error("oh!")).recover(Error.class, Throwable::getMessage);
1091+
* </code></pre>
1092+
*
1093+
* @param <X> The type of exception type to recover
1094+
* @param exceptionType {@code Class<X>} object defining exception class.
1095+
* @param f A function which takes the exception of a failure and returns a new value.
1096+
* @return A new Future.
1097+
* @throws NullPointerException if {@code f} is null
1098+
*/
1099+
default <X extends Throwable> Future<T> recover(Class<X> exceptionType, Function<? super X, ? extends T> f) {
1100+
Objects.requireNonNull(exceptionType, "exceptionType is null");
1101+
Objects.requireNonNull(f, "f is null");
1102+
return transformValue(t -> t.recover(exceptionType, f));
1103+
}
1104+
10811105
/**
10821106
* Handles a failure of this Future by returning the result of another Future.
10831107
* <p>

src/test/java/io/vavr/concurrent/FutureTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,21 @@ public void shouldRecoverFailedFuture() {
952952
assertThat(recovered.get()).isEqualTo(42);
953953
}
954954

955+
@Test
956+
public void shouldRecoverFailedFutureWithSpecificCause() {
957+
final Future<Integer> recovered = Future.<Integer> of(zZz(new Error())).recover(Error.class, t -> 42);
958+
waitUntil(recovered::isCompleted);
959+
assertThat(recovered.isSuccess()).isTrue();
960+
assertThat(recovered.get()).isEqualTo(42);
961+
}
962+
963+
@Test
964+
public void shouldNotRecoverFailedFutureWithMismatchingCause() {
965+
final Future<Integer> recovered = Future.<Integer> of(zZz(new Error())).recover(ArithmeticException.class, t -> 42);
966+
waitUntil(recovered::isCompleted);
967+
assertThat(recovered.isFailure()).isTrue();
968+
}
969+
955970
@Test
956971
public void shouldNotCrashWhenRecoverFails() {
957972
final Future<Integer> recovered = Future.<Integer> of(zZz(new Error())).recover(t -> {
@@ -962,6 +977,16 @@ public void shouldNotCrashWhenRecoverFails() {
962977
assertThat(recovered.getCause().get().getClass()).isEqualTo(ArithmeticException.class);
963978
}
964979

980+
@Test
981+
public void shouldNotCrashWhenRecoverFailsWithSpecificCause() {
982+
final Future<Integer> recovered = Future.<Integer> of(zZz(new Error())).recover(Error.class, t -> {
983+
throw new ArithmeticException();
984+
});
985+
waitUntil(recovered::isCompleted);
986+
waitUntil(recovered::isFailure);
987+
assertThat(recovered.getCause().get().getClass()).isEqualTo(ArithmeticException.class);
988+
}
989+
965990
// -- recoverWith()
966991

967992
@Test

0 commit comments

Comments
 (0)