In Java 8, is it better for interface or abstract class to define APIs returning CompletableFuture
instead of returning Future
? Considering it is ugly converting Future
to CompletableFuture
and the fact that CompletableFuture
will give the caller more flexibility of using functional style directly, what could be a good reason for an API to just return Future
?
Asked
Active
Viewed 2,854 times
13
-
2I just asked this question 2 minutes ago and 1 close vote already? What is wrong with asking for actual use cases for programming/design choices? – derrdji Jan 21 '16 at 17:59
-
I would guess its a little broad. Maybe add what the use case is? – Carlos Bribiescas Jan 21 '16 at 18:05
-
The use case is I am designing an async API that does file processing, my past knowledge tells me to to return Future
, but after learning from the other SO question I linked, I feel like Java8 is telling me to return CompletableFuture – derrdji Jan 21 '16 at 18:09. I am not sure, and need help. -
I mean, if you are going to or want the interface to provide the extra features then you should. I don't think Java 8 is telling you, forget futures, use completable futures. If the new features are useful then return the new future. Also, I'm tempted to suggest create two functions, one returning each, but that feels like a bad design but I can't say why... – Carlos Bribiescas Jan 21 '16 at 18:21
-
7Think about whether you really want to allow the caller to *complete* your future. Otherwise, if you only want to support chaining of dependent actions/processing steps, you perhaps want to return a `CompletionStage` instead. – Holger Jan 21 '16 at 19:01
-
Following on from what @Holger said, returning a `CompletionStage` does not protect the original `CompletableFuture` as you can just cast it back or call `toCompletableFuture()` on it. Maybe it is better to return `cf.whenCompleteAsync((result, error) -> {})` which creates a new `CompletableFuture`?. – jazd Oct 11 '18 at 23:04
-
1@jazd starting with Java 9, you can simply call `copy()` to get a similarly detached `CompletableFuture` or alternatively, you can return a `minimalCompletionStage()`. The latter returns a stage which can not get completed from the outside; calling `toCompletableFuture()` on it would again return a new future whose completion does not propagate back. – Holger Oct 12 '18 at 09:48
2 Answers
3
Thought I would come back to this and provide some updates on my final decisions:
For my own code/design, I went with using CompletableFuture
as the return type, because
- this is a
protected abstract
method of an internal part that I want to make extensible; - I do not need an interface to define the binding;
- the main purpose of this return type is a Future (for async IO), I personally feel the functional-styled API provided by
CompletableFuture
is an added benefit/reminder/encouragement of using functional style to the future devs.
With that being said, I would definitely use the CompletableStage
interface as the return type, had I been designing a public API, because:
- what @assylias and @Holger said about interface vs. realization and chaining ability
- and the fact that
CompletableStage
has a methodCompletableFuture<T> toCompletableFuture()
.

derrdji
- 12,661
- 21
- 68
- 78
2
My 2 cts:
- by returning a Future, you keep your options open and can return a Future, or a CompletableFuture - it makes no difference from the caller's perspective.
- by returning a CompletableFuture, you give the caller more options (they get more methods) but you also commit to returning that type of Future - if in two years you realise that returning a BetterFuture would make more sense, you will have to change the API, which is not good.
So you should probably assess the likelihood that you will want to return something other than a CompletableFuture in the future (haha) and decide accordingly.

assylias
- 321,522
- 82
- 660
- 783