To send asynchronous HTTP requests in Java using the java.net.http.HttpClient, you use the sendAsync() method. This method returns a CompletableFuture<HttpResponse<T>>, allowing you to handle the response without blocking the main thread.
Here is a step-by-step example of how to implement this:
1. Basic Asynchronous GET Request
This example demonstrates how to fire a request and handle the result using thenAccept.
package org.kodejava.httpclient;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
public class AsyncRequestExample {
public static void main(String[] args) {
// 1. Create the HttpClient
HttpClient client = HttpClient.newHttpClient();
// 2. Build the HttpRequest
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
.GET()
.build();
// 3. Send the request asynchronously
CompletableFuture<HttpResponse<String>> responseFuture =
client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
// 4. Handle the response when it arrives
responseFuture.thenAccept(response -> {
System.out.println("Status Code: " + response.statusCode());
System.out.println("Response Body: " + response.body());
}).exceptionally(ex -> {
System.err.println("Error occurred: " + ex.getMessage());
return null;
});
// The program continues here immediately while the request is in flight
System.out.println("Request sent! Doing other things...");
// Optional: Block if you need to wait for the result before the program exits
responseFuture.join();
}
}
2. Chaining and Transforming Results
Because sendAsync returns a CompletableFuture, you can chain operations like extracting the body or converting JSON.
CompletableFuture<String> bodyFuture = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body) // Transform response to just the body
.thenApply(String::toUpperCase); // Further transform the string
bodyFuture.thenAccept(System.out::println);
Key Components
sendAsync(request, bodyHandler): The non-blocking counterpart tosend().HttpResponse.BodyHandlers: Defines how to handle the incoming data (e.g.,ofString(),ofByteArray(), orofFile()).CompletableFuture: Provides methods like.thenApply()(map),.thenAccept()(consume), and.exceptionally()(error handling).
Best Practices
- Reuse the Client: Don’t create a new
HttpClientfor every request. It’s designed to be long-lived and shared. - Executor Service: By default,
HttpClientuses a default executor. For high-load applications, you can provide your own thread pool when building the client:HttpClient client = HttpClient.newBuilder() .executor(Executors.newFixedThreadPool(10)) .build(); -
Join/Get: In a console application, use
.join()or.get()at the very end to prevent themainmethod from finishing (and the JVM exiting) before the background thread completes.
