diff --git a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java index f7dbda36..6bcaf42e 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java +++ b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java @@ -1482,6 +1482,7 @@ public Cffu peekAsync(BiConsumer action, Execut // - join() // BLOCKING! // - join(timeout, unit) // BLOCKING! // - getNow(T valueIfAbsent) + // - getSuccessNow(T valueIfAbsent) // - resultNow() // - exceptionNow() // @@ -1508,6 +1509,7 @@ public Cffu peekAsync(BiConsumer action, Execut * @see #join() * @see #join(long, TimeUnit) * @see #getNow(Object) + * @see #getSuccessNow(Object) * @see #resultNow() * @see #get(long, TimeUnit) */ @@ -1532,6 +1534,7 @@ public T get() throws InterruptedException, ExecutionException { * @throws TimeoutException if the wait timed out * @see #join(long, TimeUnit) * @see #getNow(Object) + * @see #getSuccessNow(Object) * @see #resultNow() * @see #join() * @see #get() @@ -1557,6 +1560,7 @@ public T get(long timeout, TimeUnit unit) throws InterruptedException, Execution * or a completion computation threw an exception * @see #join(long, TimeUnit) * @see #getNow(Object) + * @see #getSuccessNow(Object) * @see #resultNow() * @see #get(long, TimeUnit) * @see #get() @@ -1598,6 +1602,7 @@ public T join() { * or the wait timed out(with the {@code TimeoutException} as its cause) * @see #join() * @see #getNow(Object) + * @see #getSuccessNow(Object) * @see #resultNow() * @see #get(long, TimeUnit) * @see #get() @@ -1619,6 +1624,7 @@ public T join(long timeout, TimeUnit unit) { * @throws CancellationException if the computation was cancelled * @throws CompletionException if this future completed exceptionally * or a completion computation threw an exception + * @see #getSuccessNow(Object) * @see #resultNow() * @see #join(long, TimeUnit) * @see #join() @@ -1632,6 +1638,27 @@ public T getNow(T valueIfAbsent) { return cf.getNow(valueIfAbsent); } + /** + * Returns the result value if completed successfully, else returns the given valueIfNotSuccess. + *

+ * This method will not throw exceptions + * (CancellationException/CompletionException/ExecutionException/IllegalStateException/...). + * + * @param valueIfNotSuccess the value to return if not completed successfully + * @return the result value, if completed successfully, else the given valueIfNotSuccess + * @see #getNow(Object) + * @see #resultNow() + * @see #join(long, TimeUnit) + * @see #join() + * @see #get(long, TimeUnit) + * @see #get() + */ + @Contract(pure = true) + @Nullable + public T getSuccessNow(@Nullable T valueIfNotSuccess) { + return CompletableFutureUtils.getSuccessNow(cf, valueIfNotSuccess); + } + /** * Returns the computed result, without waiting. *

@@ -1645,7 +1672,11 @@ public T getNow(T valueIfAbsent) { * .toList(); * } * + * @return the computed result + * @throws IllegalStateException if the task has not completed or the task did not complete with a result * @see #getNow(Object) + * @see #getSuccessNow(Object) + * @see #exceptionNow() */ @Contract(pure = true) @Nullable @@ -1664,6 +1695,8 @@ public T resultNow() { * @throws IllegalStateException if the task has not completed, the task completed normally, * or the task was cancelled * @see #resultNow() + * @see #getNow(Object) + * @see #getSuccessNow(Object) */ @Contract(pure = true) @Override diff --git a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java index ebaadbb4..7d27918e 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -1296,6 +1296,22 @@ public static T join(CompletableFuture cf, long timeout, TimeUnit unit) { return orTimeout(copy(cf), timeout, unit).join(); } + /** + * Returns the result value if the given stage is completed successfully, else returns the given valueIfNotSuccess. + *

+ * This method will not throw exceptions + * (CancellationException/CompletionException/ExecutionException/IllegalStateException/...). + * + * @param valueIfNotSuccess the value to return if not completed successfully + * @return the result value, if completed successfully, else the given valueIfNotSuccess + */ + @Contract(pure = true) + @Nullable + public static T getSuccessNow(CompletionStage cf, @Nullable T valueIfNotSuccess) { + final CompletableFuture f = toCf(cf); + return f.isDone() && !f.isCompletedExceptionally() ? f.join() : valueIfNotSuccess; + } + /** * Returns the computed result, without waiting. *

diff --git a/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java b/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java index bdd6211f..7071fe4d 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java +++ b/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java @@ -182,6 +182,23 @@ void test_cffuJoin() { assertEquals(42, cffu.join(3, TimeUnit.SECONDS)); } + @Test + void test_getSuccessNow() { + final Consumer> check = (cf) -> { + assertNull(cf.getSuccessNow(null)); + assertEquals(42, cf.getSuccessNow(42)); + }; + + Cffu incomplete = cffuFactory.newIncompleteCffu(); + check.accept(incomplete); + + Cffu failed = cffuFactory.failedFuture(rte); + check.accept(failed); + + incomplete.cancel(false); + check.accept(incomplete); + } + @Test void test_cffuState() { Cffu incomplete = cffuFactory.newIncompleteCffu(); diff --git a/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java b/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java index 9ae72600..31b8ae49 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java +++ b/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java @@ -8,8 +8,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import java.util.Arrays; import java.util.Collections; @@ -17,7 +15,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Supplier; import static io.foldright.cffu.CompletableFutureUtils.*; import static io.foldright.test_utils.TestUtils.*; @@ -890,6 +887,8 @@ void test_read() { final CompletableFuture completed = completedFuture(n); assertEquals(n, join(completed, 1, TimeUnit.MILLISECONDS)); + assertEquals(n, getSuccessNow(completed, anotherN)); + assertEquals(n, getSuccessNow(completed, null)); assertEquals(n, resultNow(completed)); try { exceptionNow(completed); @@ -909,6 +908,8 @@ void test_read() { } catch (CompletionException expected) { assertSame(rte, expected.getCause()); } + assertEquals(anotherN, getSuccessNow(failed, anotherN)); + assertNull(getSuccessNow(failed, null)); try { resultNow(failed); fail(); @@ -945,6 +946,8 @@ void test_read() { } catch (CompletionException expected) { assertInstanceOf(TimeoutException.class, expected.getCause()); } + assertEquals(anotherN, getSuccessNow(incomplete, anotherN)); + assertNull(getSuccessNow(incomplete, null)); try { resultNow(incomplete); fail(); diff --git a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt index fb49cd21..7dd6f869 100644 --- a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt +++ b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt @@ -963,6 +963,19 @@ fun CompletableFuture.exceptionallyComposeAsync( fun CompletableFuture.join(timeout: Long, unit: TimeUnit): T = CompletableFutureUtils.join(this, timeout, unit) as T +/** + * Returns the result value if completed successfully, else returns the given valueIfNotSuccess. + * + * This method will not throw exceptions + * (CancellationException/CompletionException/ExecutionException/IllegalStateException/...). + * + * @param valueIfNotSuccess the value to return if not completed successfully + * @return the result value, if completed successfully, else the given valueIfNotSuccess + */ +@Suppress("UNCHECKED_CAST") +fun CompletionStage.getSuccessNow(valueIfNotSuccess: T): T = + CompletableFutureUtils.getSuccessNow(this, valueIfNotSuccess) as T + /** * Returns the computed result, without waiting. * @@ -977,7 +990,7 @@ fun CompletableFuture.join(timeout: Long, unit: TimeUnit): T = * ``` */ @Suppress("UNCHECKED_CAST") -fun CompletableFuture.resultNow(): T = +fun CompletableFuture.resultNow(): T = CompletableFutureUtils.resultNow(this) as T /** diff --git a/cffu-kotlin/src/test/java/io/foldright/cffu/test/CompletableFutureExtensionsTest.kt b/cffu-kotlin/src/test/java/io/foldright/cffu/test/CompletableFutureExtensionsTest.kt index 4b97bef6..81ab6410 100644 --- a/cffu-kotlin/src/test/java/io/foldright/cffu/test/CompletableFutureExtensionsTest.kt +++ b/cffu-kotlin/src/test/java/io/foldright/cffu/test/CompletableFutureExtensionsTest.kt @@ -390,6 +390,7 @@ class CompletableFutureExtensionsTest : FunSpec({ val ff = CompletableFutureUtils.failedFuture(rte) cf.join(1, TimeUnit.MILLISECONDS) shouldBe n + cf.getSuccessNow(null) shouldBe n cf.resultNow() shouldBe n ff.exceptionNow() shouldBeSameInstanceAs rte