13

Using Java 8 great feature CompletableFuture, I'd like to transform my old async code using exceptions to this new feature. But the checked exception is something bothering me. Here is my code.

CompletableFuture<Void> asyncTaskCompletableFuture = 
                CompletableFuture.supplyAsync(t -> processor.process(taskParam));

The signature of process method:

public void process(Message msg) throws MyException;

How do I deal with that checked exception in ComletableFuture?

Stav Alfi
  • 13,139
  • 23
  • 99
  • 171
Yolanda
  • 161
  • 1
  • 2
  • 8
  • 2
    See http://stackoverflow.com/questions/18198176/java-8-lambda-function-that-throws-exception - probably to be closed as a duplicate – mtj Sep 06 '16 at 05:31
  • 4
    @mjt I think this question is worth discussing in the context of CompletableFuture, as this API has a specific handling of exceptions. – Didier L Sep 06 '16 at 08:08
  • 1
    The linked question is more general and, thus, covers this question too. – Tunaki Sep 06 '16 at 08:41
  • 1
    @Tunaki there might be more specific duplicates related to `CompletableFuture`, like http://stackoverflow.com/a/28961083/525036 and http://stackoverflow.com/q/23184964/525036 which both mention solutions involving `completeExceptionnally()` and avoiding to wrap the exception in a runtime exception. – Didier L Sep 06 '16 at 09:31
  • Here is a solution that allows you to use checked exceptions without reducing the readability of your code: https://stackoverflow.com/a/49705336/14731 – Gili Apr 07 '18 at 08:30
  • Maybe my implementation of throwing checked exception as unchecked ones is interesting for you. https://github.com/qoomon/unchecked-exceptions-java Looking forward for feedback – qoomon Jan 04 '19 at 13:40

1 Answers1

3

I have tried this way, but I don't know whether it's a good way to solve the problem.

@FunctionalInterface
public interface RiskEngineFuncMessageProcessor<Void> extends Supplier<Void> {
    @Override
    default Void get() {
        try {
            return acceptThrows();
        } catch (final Exception e) {
            throw new RuntimeException(e);
        }
    }

    Void acceptThrows() throws Exception;

With the FunctionalInterface of Supplier, I can wrap the exception:

final MyFuncProcessor<Void> func = () -> {
            processor.process(taskParam);
            return null;
        };

        CompletableFuture<Void> asyncTaskCompletableFuture =
                CompletableFuture.supplyAsync(func)
                        .thenAccept(act -> {
                            finishTask();
                        })
                        .exceptionally(exp -> {
                            log.error("Failed to consume task", exp);
                            failTask( exp.getMessage());
                            return null;
                        });
Yolanda
  • 161
  • 1
  • 2
  • 8
  • 1
    `Void` is a class from the JDK. You should not use it as a type parameter name in your interface definition. Either remove it (as it does not seem to be useful here), or use another name. Single-letter names are commonly used, I'd suggest to use `T` as it is the name used in the `Supplier` interface definition. – Didier L Sep 06 '16 at 08:57
  • 2
    It also seems that you do not need to return any results, so you should probably use [`runAsync()`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#runAsync-java.lang.Runnable-) instead of `supplyAsync()`, and [`thenRun()`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#thenRun-java.lang.Runnable-) instead of `thenAccept()`. – Didier L Sep 06 '16 at 08:59
  • 9
    I recommend to throw [`CompletionException`](https://docs.oracle.com/javase/8/docs/api/?java/util/concurrent/CompletionException.html) instead of an unspecific `RuntimeException`. I’ll work smoothly with `CompletableFuture`. – Holger Sep 06 '16 at 11:29