This article is the 9th day article of TeamLab Engineering.
In this article, I will write about Completable Future.
I don't know even if I call the official document of Completable Future Understand Java reverse recipes with one hand
CompletableFuture English version Java11 CompletableFuture Japanese version Java8 [Java Reverse Recipe](https://www.amazon.co.jp/Java%E9%80%86%E5%BC%95%E3%81%8D%E3%83%AC%E3%82%B7 % E3% 83% 94-% E7% AC% AC2% E7% 89% 88-% E7% AB% B9% E6% B7% BB-% E7% 9B% B4% E6% A8% B9 / dp / 4798158445)
Thread: The processing performed in the thread cannot be inherited after that.
future: Call to get method blocks thread
completablefuture: caller is not blocked
thenApply ・ ・ ・ The result processed in the method can be passed to the next method. thenAccept ・ ・ ・ The result processed in the method cannot be passed to the next method.
CompletableFuture<String> future1 =
CompletableFuture.supplyAsync(
() -> {
//Time-consuming process
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "java1";
});
//then Apply
future1
.thenApply(
res -> {
return res; //res contains "java1" defined in the return of future1
})
.thenApply(
res -> {
return res; //res contains the return value "java1" of the first then Apply
})
.thenAccept(
res -> {
System.out.println(res); //res contains the return value "java1" of the second Apply and is output to the console.
});
//Console output
// java1
The value of thenApply can be passed to the next thenApply.
CompletableFuture<String> future1 =
CompletableFuture.supplyAsync(
() -> {
//Time-consuming process
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "java1";
});
//then Accept
future1.thenAccept(
res -> {
System.out.println(res); // return res;Cannot be passed to the next method
});
//Console output
// java1
You cannot write return inside the thenAccept () method.
The reason can be understood by looking at the official document again.
// thenApply
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
// thenAccept
public CompletableFuture <Void> thenAccept(Consumer<? super T> action)
ThenAccept says Void in the return value, so you can't hand it over next time, I see.
Returns a new CompletionStage that will be executed when both ** this stage ** and ** the other stages specified ** have completed successfully.
[About class CompletableFuture
↓
If you interpret the above sentence so that you can understand it, ...
** This stage = future2 **
When
** Other specified stages = future3 **
When both of
** New CompletionStage to be executed = (String s1, String s2)-> s1 +" "+ s2
**
Returns
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(
() -> {
//Time-consuming process
try{
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
return "java1";
}
);
CompletableFuture<String> future2 = future1.thenApply(
s -> {
//Time-consuming process
try{
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
return "java2";
}
);
CompletableFuture<String> future3 = future1.thenApply(
s -> {
//Time-consuming process
try{
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
return "java3";
}
);
//In thenCombine, future2 and the first argument(future3)When both of them are completed normally
// (String s1, String s2) -> s1 + " " +Running s2
future2.thenCombine(future3, (String s1, String s2) -> s1 + " " + s2)
.thenAccept(System.out::println);
//Console output
// java2 java3
Some methods that set callbacks have "Async" at the end of the method name. "With Async" Executed on the same thread as the previous task "No Async" Threads are assigned as new tasks
thenApply ・ ・ ・ Executed in the order of future1 → future3 → future2 thenApplyAsync ・ ・ ・ After executing future4, future5 and future6 will be executed in parallel.
thenApply
Returns a new CompletionStage that will be executed when this stage completes successfully, with the result of this stage set as an argument to the specified function. thenApply
With the code below Executed in the order of future1 → future3 → future2
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(
() -> {
//Time-consuming process
try{
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
return "java1";
}
);
CompletableFuture<String> future2 = future1.thenApply(
s -> {
//Time-consuming process
try{
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
return "java2";
}
);
CompletableFuture<String> future3 = future1.thenApply(
s -> {
//Time-consuming process
try{
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
return "java3";
}
);
//Executed in the order of future1 → future3 → future2
future2.thenCombine(future3, (String s1, String s2) -> s1 + " " + s2)
.thenAccept(System.out::println);
//Console output
// java2 java3
thenApplyAsync
When this stage completes successfully, it sets the result of this stage as an argument to the specified function and returns a new CompletionStage that will be executed using the stage's default asynchronous execution capabilities. thenApplyAsync
If you interpret it in your own way ** When this stage (future4) ** completes successfully The result of this stage To the specified function () Set to ** argument (s in lambda expression) **, Using the default asynchronous execution feature of this stage ** Executed (contents of lambda expression) ** Returns a new CompletionStage.
With the code below After executing future4, future5 and future6 will be executed in parallel
CompletableFuture<String> future4 =
CompletableFuture.supplyAsync(
() -> {
//Time-consuming process
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "java4";
});
CompletableFuture<String> future5 =
future4.thenApplyAsync(
s -> {
//Time-consuming process
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "java5";
});
CompletableFuture<String> future6 =
future4.thenApplyAsync(
s -> {
//Time-consuming process
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "java6";
});
//After executing future4, future5 and future6 will be executed in parallel
future5
.thenCombine(future6, (String s1, String s2) -> s1 + " " + s2)
.thenAccept(System.out::println);
//Console output
// java5 java6
If asynchronous processing (supplyAsync) fails with an exception, the callback specified in the thenApply or thenAccept method will not be called. In this case, handle using the whenComplete () method or exceptionally () method.
If you read this, you usually use thenApply
thenCompose Returns a new CompletionStage that will be executed when this stage completes successfully, with ** this stage set as a ** argument to the specified function.
thenApply Returns a new CompletionStage that will be executed when this stage completes successfully, with ** the result of this stage set to the ** argument to the specified function.
public <U> CompletableFuture<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
I can't tell the difference by reading the official documentation ...
I'm studying Completable Future. Confused with then Apply and then Compose. Postscript: And I learned a lot from Mr. Uragami! (∩´∀ `) ∩Why "One of the uses of thenCompose is that I already have an API that returns a CompletableFuture, and I thought it would be time to combine it."
Please refer to this article If you already have an API that returns a Completable Future, thenCompose When creating a new one, thenApply As you can see, I roughly understand that I should use thenApply for the basics.
I didn't know how to use the thenApply method and when it was executed, so I'm glad I took this opportunity to know it.
Recommended Posts