CompletableFuture исключительно () и handle () проглатывают исключение RuntimeException? - PullRequest
1 голос
/ 13 июля 2020

У меня есть следующее:

cflst.addAll(asList(
            supplyAsync(() -> mytask.getComp("comp"), executor)
                    .thenAccept(comp -> helper.mapStuff(comp))
                    .exceptionally(ex -> {
                        sout("Some Error");  // Never print
                        return null;
                    })
                    .handle((comp, throwable) -> {
                        sout("Error here" + comp); //always prints regarless of exception
                        return null;
                    }),

    ...

    ));

 CompletableFuture.allOf(cflst.toArray(new CompletableFuture[0])).join();

И MyTask.getComp метод

 CompX getComp(String id) {
     client.getData(id);
  }

Client.getData()

 SomeX getData(String id) {
    throw new MyCustomRuntimeException("Blew Up");
 }
  

Я подумал, когда исключение выброшенный в метод myComp, блок exceptionally() получает исключение. Но это не похоже.

Также, независимо от исключения, handle() всегда вызывается!?!?!

Я хочу иметь возможность перехватывать любое исключение и обрабатывать его по мере необходимости (Либо повторно выбросить, либо проглотить).

Обновление

Когда я перехватываю исключение в методе getComp, а затем повторно выбрасываю его, выполняется блок exceptionally. Но не уверен, почему он не запускается, когда исключение выбрасывается еще на один уровень вниз с помощью метода getData?

Ответы [ 2 ]

1 голос
/ 13 июля 2020

В вашем примере вы последовательно составляете CompletableFuture s.

После .exceptionally() вы получаете future, который возвращает null вместо того, чтобы генерировать исключение. Следовательно, последующий .handle() никогда не будет наблюдать исключение.

Если вы хотите, чтобы .handle() получил такое же исключение, вы должны вызвать его в том же будущем, где вы вызываете .exception(). Например, используйте переменную, чтобы сохранить будущее, которое вы получите после .thenAccept(), а затем составьте на нем .exceptionally() и .handle(), а не последовательно.

Однако вы должны выбрать между .exceptionally() и .handle():

  • .exceptionally() обычно используется для возврата значения по умолчанию вместо разрешения исключения через

  • .handle() обычно используется для регистрации, преобразования и / или обертывания исключения как блока catch; не забудьте повторно создать исключение, если хотите, чтобы исключение было от go до

Для действий по очистке, таких как блок finally, более подходит .whenComplete().

1 голос
/ 13 июля 2020

Этап, созданный методом handle(), всегда выполняется независимо от того, возникает исключение или нет, тогда как этап exceptionally() выполняется только при возникновении исключения.

Мне не удалось воспроизвести вашу ошибку, exceptionally блок выполняется для меня всякий раз, когда исключение не обнаружено.

На мой взгляд, вы должны использовать либо handle, либо exceptionally.

handle() метод позволяет вам указать значение по умолчанию значение при исключении и exceptionally() метод аналогичен обработке, но менее подробен

...