I can't understand even if I read the official document of CompletableFuture, so I understand Java reverse recipe with one hand

This article is the 9th day article of TeamLab Engineering.

In this article, I will write about Completable Future.

background

I don't know even if I call the official document of Completable Future Understand Java reverse recipes with one hand

Reference URL Reference book

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)

Types of concurrency, differences

Thread: The processing performed in the thread cannot be inherited after that.

future: Call to get method blocks thread

completablefuture: caller is not blocked

Difference between then Apply and then Accept

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.

then Apply


    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.

then Accept


    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.

What is thenCombine?

Returns a new CompletionStage that will be executed when both ** this stage ** and ** the other stages specified ** have completed successfully. [About class CompletableFuture --then Combine](https://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/CompletableFuture.html#thenCombine-java.util.concurrent.CompletionStage -java.util.function.BiFunction-)

↓ 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

Difference between thenApply and thenApplyAsync

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

Completable Future error handling

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.

whenComplete

exceptionally

Difference between then Compose and then Apply

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.

Summary

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

I can't understand even if I read the official document of CompletableFuture, so I understand Java reverse recipe with one hand
I can't input Japanese with VS code (Visual Studio Code) of Ubuntu 18.04.5! ?? If you want to download VS Code to Ubuntu, go to the official website! !!
I didn't understand the behavior of Java Scanner and .nextLine ().
I passed the Oracle Java Bronze, so I summarized the outline of the exam.