What is the CompletableFuture equivalent of Streams peek()?

An answer here quotes a table of all CompletableFuture methods, but it's not quite what I'm looking for, or perhaps I'm going about it wrong.

I'm looking for the CompletableFuture equivalent of Streams' peek(), so basically a thenApply that returns the input argument or a thenRun that doesn't return Void. There are two ways I can think of that both don't semantically accurately express my intention, but do the job:

(..)
.thenApply((a) -> {
   doSomething();
   return a;
}
(..)

and

(..)
.whenComplete((result, exception) -> {
   if (exception == null) {
      doSomething();
   }
}
(..)

Both take the input from the previous stage, allow me to perform an action and return with the same type to the next stage. Of these two the latter second approach limits my timing to when everything else is done, rather than async as soon as the previous necessary stage is complete.

I've also been searching for an identity function that takes a consumer function as argument, but it seems I would have to write that myself:

public static <T> Function<T, T> identityConsumer(Consumer<T> c) {
    return a -> { c.accept(a); return a; };
}
(..)
.thenApply(identityConsumer(a -> doSomething()));
(..)

So short of writing my own util functions, is there an elegant way of performing an action in an intermediate stage, where I don't have to return something, while keeping the stage's current type?


Unlike with Stream, you can make multiple function chains from a single future, so it is not necessary to do everything in a single chain of calls. I would approach your problem like so:

var f1 = CompletableFuture.supplyAsync(...);
f1.thenRun(() -> doSomething()); // this is your "peek"
var f2 = f1.thenApply(...); // continue your chain of operations here