es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

CompletableFuture no funciona si se guarda en una variable.

¿Por qué no funciona cuando guardo el futuro en una variable antes de los pasos de configuración?

@Test
void simple() {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(this::throwException)
            .exceptionally(throwable -> HANDLED);
    assertEquals(HANDLED, future.join());
}

@Test
void withVar() {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(this::throwException);
    future.exceptionally(throwable -> HANDLED);
    assertEquals(HANDLED, future.join());
}

private String throwException() {
    if (true) {
        throw new RuntimeException(FAIL);
    }
    return SUCCESS;
}

simple() está bien, pero withVar() no funciona:

java.util.concurrent.CompletionException: java.lang.RuntimeException: FAIL

en java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
en java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
en java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702)
en java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692)
en java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
en java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
en java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
en java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
en java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)`
Causado por: java.lang.RuntimeException: FAIL
    en ru.dionisis.resttest.ComplitableFutureTest.throwException(ComplitableFutureTest.java:35)
    en java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
    ... 6 más`

Hubo un problema similar con RestTemplateBuilder, cuando quería hacer opcional la inicialización de un campo

Tags:  ,

Answer

  1. Avatar for davy.ai

    El problema con withVar() es que exceptionally devuelve un nuevo CompletableFuture con el valor de error manejado, pero no modifica el CompletableFuture original que se guardó en la variable future. Por lo tanto, cuando se llama a join() en future, todavía contiene la excepción no manejada y provoca que la prueba falle.

    En simple(), el método exceptionally se llama directamente en el CompletableFuture, por lo que el manejo se aplica al mismo futuro que se une posteriormente.

    Para solucionar el problema con withVar(), puede guardar el nuevo CompletableFuture devuelto por exceptionally en la variable future, de esta manera:

    @Test
    void withVar() {
        CompletableFuture<string> future = CompletableFuture.supplyAsync(this::throwException);
        future = future.exceptionally(throwable -> HANDLED);
        assertEquals(HANDLED, future.join());
    }
    

    De esta manera, la variable future apunta al nuevo objeto CompletableFuture que contiene el valor de error manejado y join() devuelve el resultado esperado.

Comments are closed.