21

私はとコールバックListenableFutureを使ったパターンに慣れています。onSuccess()onFailure()

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
ListenableFuture<String> future = service.submit(...)
Futures.addCallback(future, new FutureCallback<String>() {
  public void onSuccess(String result) {
    handleResult(result);
  }
  public void onFailure(Throwable t) {
    log.error("Unexpected error", t);
  }
})

Java 8CompletableFutureは、多かれ少なかれ同じユースケースを処理することを意図しているようです。単純に、上記の例を次のように翻訳し始めることができます。

CompletableFuture<String> future = CompletableFuture<String>.supplyAsync(...)
  .thenAccept(this::handleResult)
  .exceptionally((t) -> log.error("Unexpected error", t));

これは確かにバージョンよりも冗長ではなく、ListenableFuture非常に有望に見えます。

ただし、 をとらないため、コンパイルされませexceptionally()ん。この場合は.Consumer<Throwable>Function<Throwable, ? extends T>Function<Throwable, ? extends String>

これは、単にエラーをログに記録することはできず、エラーの場合に返す値を考え出す必要がStringあり、エラーの場合に返す意味のある値がないことを意味Stringします。nullコードをコンパイルするためだけに、を返すことができます。

  .exceptionally((t) -> {
    log.error("Unexpected error", t);
    return null; // hope this is ignored
  });

しかし、これは再び冗長になり始めており、冗長性を超えて、それが浮かんでいるのは好きではありません.null誰かがその値を取得またはキャプチャしようとする可能性があり、かなり後の時点で予期しNullPointerExceptionない

もし私が少なくともこのようなことをexceptionally()することができたなら -Function<Throwable, Supplier<T>>

  .exceptionally((t) -> {
    log.error("Unexpected error", t);
    return () -> { 
      throw new IllegalStateException("why are you invoking this?");
    }
  });

--しかし、そうではありません。

exceptionally()が有効な値を生成してはならない場合、どうするのが正しいでしょうか? このユースケースをより適切にサポートするために、私ができることCompletableFuture、または新しい Java 8 ライブラリーで他にできることはありますか?

4

2 に答える 2

3

exceptionally(Function<Throwable,? extends T> fn)も返すことに注意してくださいCompletableFuture<T>。だからあなたはさらに連鎖することができます。

の戻り値はFunction<Throwable,? extends T>、次に連鎖するメソッドのフォールバック結果を生成するためのものです。たとえば、DB から値を取得できない場合は、キャッシュから値を取得できます。

CompletableFuture<String> future = CompletableFuture<String>.supplyAsync(/*get from DB*/)
  .exceptionally((t) -> {
    log.error("Unexpected error", t);
    return "Fallback value from cache";
  })
  .thenAccept(this::handleResult);

関数の代わりにexceptionally受け入れる場合、どうすればさらにチェーンするために a を返すことができますか?Consumer<T>CompletableFuture<String>

exceptionallyを返すバリアントが必要だと思いますvoid。しかし、残念ながら、いいえ、そのような変種はありません。

したがって、このオブジェクトを返さず、コードでそれ以上使用しない場合は、このフォールバック関数から任意の値を安全に返すことができfutureます (したがって、さらに連鎖することはできません)。変数に代入しないほうがいいです。

CompletableFuture<String>.supplyAsync(/*get from DB*/)
  .thenAccept(this::handleResult)
  .exceptionally((t) -> {
    log.error("Unexpected error", t);
    return null;
  });
于 2016-06-12T04:30:48.560 に答える