Java 11 HttpClient — Modern HTTP Client with HTTP/2 and Async
Fast recall
Quick revision
Core answer
HttpURLConnection. It supports HTTP/1.1 and HTTP/2 (negotiated transparently), WebSocket, synchronous and asynchronous APIs (send and sendAsync returning CompletableFuture> ), request/response body handlers (byte arrays, strings, streams, files, JSON via custom handlers), connection pooling, HTTP/2 multiplexing, redirect policies, timeouts, and TLS/authentication. It's built on a builder pattern: HttpClient.newBuilder().connectTimeout(...).version(HTTP_2).build() for the client, and HttpRequest.newBuilder().uri(...).header(...).POST(body).build() for requests. Compared to `HttpURLConnection` (the pre-Java-11 JDK option), it's vastly cleaner, supports HTTP/2, has built-in async, and doesn't require you to manually wire input/output streams. Compared to Apache HttpClient / OkHttp, it's JDK-native (no dependency), covers most use cases, but has fewer extension points (interceptors, rich logging, advanced proxy handling). For typical REST calls, JDK HttpClient is now the default choice — especially paired with virtual threads on Java 21 where the synchronous API scales to massive concurrency without a reactive stack. For complex needs (interceptors, custom auth flows, very specific timeouts), Apache/OkHttp still wins.Whether the candidate knows the Java 11 HttpClient API shape (builder, BodyPublisher/BodyHandler, send/sendAsync), its HTTP/2 + WebSocket support, and how it compares to HttpURLConnection and Apache/OkHttp
Confusing BodyPublisher (request body) with BodyHandler (response body). Thinking the API is blocking-only. Forgetting it uses HTTP/2 by default when server supports it
Mention HTTP/2 multiplexing and stream ID handling, discuss the synergy with Java 21 virtual threads (synchronous API scales to millions), show a CompletableFuture pipeline with proper error handling, and note the WebSocket API
Interview-ready guide
Interview answer
Java 11's HttpClient is a modern, built-in HTTP client in java.net.http. It replaces the painful HttpURLConnection and gives the JDK a competitive alternative to Apache HttpClient or OkHttp.
What it supports
- HTTP/1.1 and HTTP/2 (automatic ALPN negotiation)
- WebSocket
- Synchronous (
send) and asynchronous (sendAsyncreturningCompletableFuture) APIs - Connection pooling and HTTP/2 multiplexing
- Redirects, timeouts, TLS, proxy, authentication
- Body handlers for common shapes: string, byte[], file, input stream, line stream, discard
Builder pattern for client and request
- Create
HttpClientonce, reuse — thread-safe - Requests are immutable; build fresh per call
The two body concepts — don't confuse
- `BodyPublisher`: request body source —
ofString,ofByteArray,ofFile,ofInputStream - `BodyHandler`: response body sink —
ofString,ofByteArray,ofFile(path),ofLines,discarding
Basic GET
HttpRequest.newBuilder().uri(...).header(...).GET().build()client.send(req, BodyHandlers.ofString())→HttpResponse.statusCode(),.headers(),.body()
Basic POST with JSON
.header("Content-Type", "application/json").POST(BodyPublishers.ofString(json))
Async with CompletableFuture
client.sendAsync(req, BodyHandlers.ofString())- Returns
CompletableFuture> - Chain with
.thenApply,.thenCompose,.exceptionally - Fan-out/fan-in with
CompletableFuture.allOf
WebSocket
client.newWebSocketBuilder().buildAsync(uri, listener)- Listener has
onOpen,onText,onBinary,onClose,onError - Backpressure via
ws.request(n)
Java 21 virtual threads change the game
- Use the synchronous API with
Executors.newVirtualThreadPerTaskExecutor() - Scales to millions of concurrent blocking HTTP calls
- Sequential-style code, no
CompletableFuturechains HttpClientuses NIO internally — no pinning issues with virtual threads- Stack traces point at your code, not async frames
vs `HttpURLConnection`
- HttpClient wins on every axis: cleaner, HTTP/2, async, pooling, WebSocket
HttpURLConnectionis legacy; avoid for new code
vs Apache HttpClient 5.x
- Apache: richer features — interceptors, custom auth, cookie stores, per-phase timeouts
- JDK: no dependency, simpler, covers 90% of use cases
- Pick Apache for enterprise needs (interceptors, advanced logging)
vs OkHttp
- OkHttp: great for Android, elegant interceptor chain, built-in response caching
- JDK: simpler server-side
- OkHttp's interceptor model is its biggest advantage
vs Spring
RestTemplate: legacy, wraps HttpURLConnection or ApacheWebClient: reactive (Project Reactor); overkill for simple RESTRestClient(Spring 6.1+): non-reactive, fluent, wraps JDK HttpClient — the current Spring default
Pitfalls
- Don't create a new client per request — holds pools; reuse a singleton
- BodyPublisher vs BodyHandler confusion — Publisher is request body, Handler is response body
- No built-in JSON — pair with Jackson/Gson/Moshi
- Timeouts:
connectTimeouton client for handshake,.timeout(...)per request for end-to-end - HTTP/2 server push exists but rarely useful; ignore
Recommendation: For plain Java REST calls, the JDK `HttpClient` is now the default choice — no dependency, HTTP/2, async, and WebSocket out of the box. Create one client singleton and reuse it; the connection pool and HTTP/2 multiplexing are your friends. On Java 21, pair the synchronous API with virtual threads (newVirtualThreadPerTaskExecutor) to get massive concurrency without CompletableFuture ceremony — sequential code, millions of concurrent calls. Reach for Apache HttpClient or OkHttp when you genuinely need interceptors, advanced cookie/auth flows, or rich logging frameworks. For Spring, use `RestClient` (Spring 6.1+) which wraps JDK HttpClient with a fluent API, or `WebClient` if you're already on a reactive stack. Don't confuse BodyPublisher (request body) with BodyHandler (response body) — that's the main API-learning curve. Always pair with a JSON library (Jackson/Gson/Moshi) since there's no built-in JSON support.
Java 11 `HttpClient` — Modern HTTP Client with HTTP/2 and Async
Direct Answer
The java.net.http.HttpClient (Java 11, JEP 321) is a modern, built-in HTTP client that replaces the old, painful HttpURLConnection. It supports HTTP/1.1 and HTTP/2 (negotiated transparently), WebSocket, synchronous and asynchronous APIs (send and sendAsync returning CompletableFuture<HttpResponse<T>>), request/response body handlers (byte arrays, strings, streams, files, JSON via custom handlers), connection pooling, HTTP/2 multiplexing, redirect policies, timeouts, and TLS/authentication. It's built on a builder pattern: HttpClient.newBuilder().connectTimeout(...).version(HTTP_2).build() for the client, and HttpRequest.newBuilder().uri(...).header(...).POST(body).build() for requests. Compared to HttpURLConnection (the pre-Java-11 JDK option), it's vastly cleaner, supports HTTP/2, has built-in async, and doesn't require you to manually wire input/output streams. Compared to Apache HttpClient / OkHttp, it's JDK-native (no dependency), covers most use cases, but has fewer extension points (interceptors, rich logging, advanced proxy handling). For typical REST calls, JDK HttpClient is now the default choice — especially paired with virtual threads on Java 21 where the synchronous API scales to massive concurrency without a reactive stack. For complex needs (interceptors, custom auth flows, very specific timeouts), Apache/OkHttp still wins.
Common Mistakes & Pitfalls
Confusing BodyPublisher (request body) with BodyHandler (response body). Thinking the API is blocking-only. Forgetting it uses HTTP/2 by default when server supports it
Check your understanding
Answer these without looking back at the article.
- What's the difference between `BodyPublisher` and `BodyHandler`?
- How do `HttpClient` and virtual threads interact on Java 21?
- When would you prefer Apache HttpClient over the JDK `HttpClient`?
- How does HTTP/2 multiplexing affect connection pooling?
- How do you handle retries with `CompletableFuture.thenCompose`?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.