// , BiFunction<T, U,R> { R apply(T t, U u); } // , BiConsumer<T,U> { void accept(T t, U u) } // , Function<T, R> { R apply(T t); } // , Consumer<T> { void accept(T t); } // , Supplier<T> { T get(); }
// , Runnable { void run(); }
CompletableFuture
class has two sub-interfaces - for writing and for reading, which in turn are divided into direct (synchronous) and mediated (asynchronous). Only the sub-interface of direct reading ( java.util.concurrent.Future
, existing since java 5) is programmatically highlighted, but for classification purposes it is useful to mentally select the others. In addition to this separation by sub-interfaces, I will also try to separate the basic methods and methods that implement particular cases. boolean complete(T value) boolean completeExceptionally(Throwable ex)
with obvious semantics. boolean cancel(boolean mayInterruptIfRunning)
equivalent to completeExceptionally(new CancellationException)
. Introduced for compatibility with java.util.concurrent.Future. static <U> CompletableFuture<U> completedFuture(U value)
equivalent to CompletableFuture res=new CompletableFuture(); res.complete(value)
CompletableFuture res=new CompletableFuture(); res.complete(value)
. void obtrudeValue(T value) void obtrudeException(Throwable ex)
Forcibly overwrite the stored value. A surefire way to shoot yourself in the foot. boolean isDone()
Checks whether the result has already been recorded in this futures. T get()
Waits if the result is not yet recorded, and returns a value. If an exception was written, throws a ExecutionException. boolean isCancelled()
checks whether an exception was written using the cancel () method. T join()
Same as get (), but throws a CompletionException. T get(long timeout, TimeUnit unit)
get()
with timeout. T getNow(T valueIfAbsent)
returns the result immediately. If the result has not yet been recorded, returns the value of the valueIfAbsent
parameter. int getNumberOfDependents()
approximate number of other CompletableFuture waiting to be filled. static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
The task with the supplier function is started, and the result of the execution is written to the futures. The task is run on a standard thread pool. static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
The same, but running on the thread pool specified by the executor parameter. static CompletableFuture<Void> runAsync(Runnable runnable) static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
The same as supplyAsync
, but the action of the Runnable
type and, accordingly, the result will be of the Void
type.ForkJoinPool.commonPool()
, or on the stream indicated by the additional parameter). Further only methods for synchronous start will be described.CompletableFuture
for accessing the result of the reaction execution. They differ in the type of reaction. <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
The main method in which the reaction gets the value from the futures and the return value is transferred to the resulting futures. CompletableFuture<Void> thenAccept(Consumer<? super T> block)
The reaction retrieves the value from the futures, but does not return the value, soVoid
. CompletableFuture<Void> thenRun(Runnable action)
The reaction does not receive or return a value. supplyAsync(compute1) .thenApply(compute2) .thenApply(compute3) .thenAccept(compute4);
compute4(compute3(compute2(compute1())));
<U> CompletableFuture<U> thenCompose(Function<? super T, CompletableFuture<U>> fn)
Same as thenApply
, but the reaction itself returns futures instead of the finished value. This may be necessary if you want to use a complex topology reaction. static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
Returns a new futures contract that is filled in when any of the futures cfs
parameter is cfs
. The result is the same as the result of the completed futures. <U> CompletableFuture<U> applyToEither(CompletableFuture<? extends T> other, Function<? super T,U> fn)
Returns a new futures, which is filled when this futures or futures, transmitted by the parameter other
. The result is the same as the result of the completed futures. CompletableFuture.anyOf(this, other).thenApply(fn);
CompletableFuture<Void> acceptEither(CompletableFuture<? extends T> other, Consumer<? super T> block) CompletableFuture<Void> runAfterEither(CompletableFuture<?> other, Runnable action)
<T> CompletableFuture<T> either(CompletableFuture<? extends T> other) { return CompletableFuture.anyOf(this, other); }
f1.applyToEither(other, fn) == f1.either(other).thenApply(fn); f1.applyToEitherAsync(other, fn) == f1.either(other).thenApplyAsync(fn); f1.applyToEitherAsync(other, fn, executor) == f1.either(other).thenApplyAsync(fn, executor); f1.acceptEither(other, block) == f1.either(other).thenAccept(other); f1.runAfterEither(other, action) == f1.either(other).thenRun(action);
<U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)
The main method. It has two futures input, the results of which are accumulated and then transferred to the reaction, which is a function of two parameters. <U> CompletableFuture<Void> thenAcceptBoth(CompletableFuture<? extends U> other, BiConsumer<? super T,? super U> block)
reaction does not return value CompletableFuture<Void> runAfterBoth(CompletableFuture<?> other, Runnable action)
the reaction takes no parameters and does not return a value static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
Returns a CompletableFuture ending on completion of all futures in the parameter list. The obvious disadvantage of this method is that the resulting futures do not transfer the values ​​obtained in the futures parameters, so that if they are needed, they must be transferred in some other way. CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
If this futures failed, the resulting futures will end with the result produced by the function fn
. If the futures finished normally, then the resulting futures will end normally with the same result. <U> CompletableFuture<U> handle(BiFunction<? super T,Throwable,? extends U> fn)
In this method, the reaction is always invoked, regardless of whether the given futures fail normally or abnormally. If the futures ended normally with the result r
, then the parameters (r, null)
will be passed to the reaction, if it crashes with the exception of ex, the parameters (null, ex)
will be passed to the reaction. The result of the reaction may be of a different type than the result of the futures. CompletableFuture<Integer> safe = future.handle((r, ex) -> { if (r != null) { return Integer.parseInt(r); } else { log.warn("Problem", ex); return -1; } });
future
produces a String
result or an error, the reaction translates the result into an integer, and in case of an error, it returns -1. Note that, in general, the test should start with if (ex!=null)
, since r==null
can be both at abnormal and normal termination, but in this example, the case of r==null
treated as an error.Source: https://habr.com/ru/post/213319/
All Articles