JDK8 CompletableFuture.supplyAsync как бороться с interruptedException

CompletableFuture.supplyAsync(
() -> {
    transporter.write(req);
    //here take the value from a blocking queue,will throw a interruptedException
    return responseQueue.take();
},  executorService);

Общим методом борьбы с interruptedException является либо прерывание снова, либо прямой throw interruptedException, но оба они не могут работать. У кого-нибудь есть идея?

Ответ 1

Я изменяю код следующим образом.

    CompletableFuture<Rep> result = new CompletableFuture<>();
    CompletableFuture.runAsync(() -> {

        transporter.write(req);
        try {
            Rep rep = responseQueue.take();
            result.complete(rep);
        } catch (InterruptedException e) {
            result.completeExceptionally(e);
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            result.completeExceptionally(e);
        }

    }, executorService);
    return result;

Ответ 2

Поскольку функции лямбда не поддерживают исключение броска, я думаю, что разработчикам Java понадобится новая парадигма. Одна вещь, которая приходит на ум, такова:

public class ResultWrapper<R, E extends Exception> {
    E exception;
    R result;
}

Лямбда-функции могут возвращать экземпляры этой оболочки. (Изменить: ваш случай)

CompletableFuture<ResultWrapper<String, InterruptedException>> aFuture = ...;
...
aFuture.supplyAsync(
() -> {
    try {
        transporter.write(req);
    } catch(InterruptedException e) {
        ResultWrapper<String, InterruptedException> r = new ResultWrapper<>();
        r.exception = e;
        r.result = null;
        return r;
    }
    ...
},  executorService);

Ответ 3

Я столкнулся с тем же вопросом, но, прочитав больше комментариев отсюда и справочника, я думаю, вы можете сделать одно из этих двух:

1 (что я делаю):

CompletableFuture.runAsync(() -> {
    transporter.write(req);
    try {
        Rep rep = responseQueue.take();
        result.complete(rep);
    } catch (Exception e) {
        throw new CompletionException(e);
    }
}, executorService);
return result;

или 2:

CompletableFuture<Rep> result = new CompletableFuture<>();
new Thread(()-> {
    transporter.write(req);
    try {
        Rep rep = responseQueue.take();
        result.complete(rep);
    } catch (Exception e) {
        retsult.completeExceptionally(e);
    }
}).start();

Я знаю, что второй не использует executorService, но я чувствую, что вся цель использования CompletableFuture - использование API CompletionStage в функциональном стиле.

Ответ 4

@antak упомянул об этом в комментариях, но я думаю, что правильный ответ здесь:

Для CompletableFuture.supplyAsync() оберните его в java.util.concurrent.CompletionException и перебросьте его.

Таким образом, пример кода будет выглядеть примерно так:

CompletableFuture.supplyAsync(
    () -> {
        transporter.write(req);
        try {
            //here take the value from a blocking queue,will throw a interruptedException
            return responseQueue.take();
        }
        catch (InterruptedException e) {
            throw new CompletionException(e);
        }
    },  executorService);