Skip to main content

Ch 16.2 URL, URLConnection, and the Modern HTTP Client

1. URL — Uniform Resource Locator

A URL is the standard addressing scheme for resources on the internet (web pages, images, files, API endpoints, etc.). It has the following structure:

https://www.example.com:443/search?q=java&lang=en#results
ComponentExampleDescription
ProtocolhttpsCommunication rule (http, https, ftp)
Hostwww.example.comServer domain or IP
Port443Default for HTTPS
Path/searchResource path on the server
Query?q=java&lang=enAdditional parameters
Fragment#resultsSection within the page

Java's java.net.URL class parses and manages URL strings.

import java.net.URL;
import java.net.MalformedURLException;

public class URLParsingExample {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("https://www.example.com:443/search?q=java&lang=en");

System.out.println("Protocol: " + url.getProtocol()); // https
System.out.println("Host: " + url.getHost()); // www.example.com
System.out.println("Port: " + url.getPort()); // 443
System.out.println("Path: " + url.getPath()); // /search
System.out.println("Query: " + url.getQuery()); // q=java&lang=en
System.out.println("Full URL: " + url.toString());
}
}

2. URLConnection — Fetching Web Content

URLConnection represents a connection to a URL. You can use it to read response headers and download the response body as a stream.

import java.io.*;
import java.net.*;

public class URLConnectionExample {
public static void main(String[] args) {
try {
URL url = new URL("https://www.example.com");
URLConnection conn = url.openConnection();

conn.setRequestProperty("User-Agent", "JavaApp/1.0");
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);

System.out.println("Content-Type: " + conn.getContentType());
System.out.println("Content-Length: " + conn.getContentLength());

// Read the HTML source of the page
try (BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), "UTF-8"))) {
String line;
int count = 0;
while ((line = br.readLine()) != null && count < 20) {
System.out.println(line);
count++;
}
}

} catch (IOException e) {
e.printStackTrace();
}
}
}

3. HttpURLConnection — HTTP GET and POST

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;

public class HttpURLConnectionExample {

// HTTP GET request
public static String get(String urlStr) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);

int code = conn.getResponseCode();
System.out.println("GET " + urlStr + " -> HTTP " + code);

if (code != HttpURLConnection.HTTP_OK) {
throw new IOException("HTTP error: " + code);
}

StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append('\n');
}
}
conn.disconnect();
return sb.toString();
}

// HTTP POST request with JSON body
public static String post(String urlStr, String jsonBody) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true);
conn.setConnectTimeout(5000);

try (OutputStream os = conn.getOutputStream()) {
os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
}

int code = conn.getResponseCode();
System.out.println("POST -> HTTP " + code);

InputStream is = (code >= 200 && code < 300)
? conn.getInputStream()
: conn.getErrorStream();

StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(is, StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append('\n');
}
}
conn.disconnect();
return sb.toString();
}

public static void main(String[] args) {
try {
String response = get("https://jsonplaceholder.typicode.com/todos/1");
System.out.println("Response:\n" + response);

String json = "{\"title\":\"Learn Java\",\"completed\":false,\"userId\":1}";
String created = post("https://jsonplaceholder.typicode.com/todos", json);
System.out.println("Created:\n" + created);

} catch (IOException e) {
e.printStackTrace();
}
}
}

4. Java 11 HttpClient — The Modern Approach

Java 11 introduced java.net.http.HttpClient — a clean, powerful HTTP client with HTTP/2 support, async operations, and a fluent API.

import java.net.http.*;
import java.net.URI;
import java.time.Duration;

public class HttpClientExample {
public static void main(String[] args) throws Exception {

// Build a reusable client
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(5))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();

// Synchronous GET
HttpRequest getRequest = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/todos/1"))
.header("Accept", "application/json")
.timeout(Duration.ofSeconds(10))
.GET()
.build();

HttpResponse<String> getResponse = client.send(
getRequest, HttpResponse.BodyHandlers.ofString());

System.out.println("Status: " + getResponse.statusCode());
System.out.println("Body: " + getResponse.body());

// Synchronous POST with JSON body
String json = "{\"title\":\"Test Post\",\"userId\":1}";
HttpRequest postRequest = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();

HttpResponse<String> postResponse = client.send(
postRequest, HttpResponse.BodyHandlers.ofString());

System.out.println("POST status: " + postResponse.statusCode());
System.out.println("POST body: " + postResponse.body());
}
}

5. Asynchronous Requests: sendAsync()

import java.net.http.*;
import java.net.URI;
import java.util.concurrent.*;
import java.util.List;

public class AsyncHttpExample {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();

List<String> urls = List.of(
"https://jsonplaceholder.typicode.com/todos/1",
"https://jsonplaceholder.typicode.com/todos/2",
"https://jsonplaceholder.typicode.com/todos/3"
);

// Fire all requests concurrently
List<CompletableFuture<String>> futures = urls.stream()
.map(url -> client.sendAsync(
HttpRequest.newBuilder().uri(URI.create(url)).build(),
HttpResponse.BodyHandlers.ofString())
.thenApply(res -> "HTTP " + res.statusCode() + ": " + res.body()))
.toList();

// Wait for all and print results
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

for (int i = 0; i < futures.size(); i++) {
System.out.println("[" + urls.get(i) + "]\n" + futures.get(i).get());
}
}
}

6. Practical Example: REST API Client

import java.net.http.*;
import java.net.URI;
import java.time.Duration;

public class RestApiClient {

static final HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
static final String BASE = "https://jsonplaceholder.typicode.com";

public static String getTodo(int id) throws Exception {
HttpResponse<String> res = client.send(
HttpRequest.newBuilder()
.uri(URI.create(BASE + "/todos/" + id))
.header("Accept", "application/json")
.GET().build(),
HttpResponse.BodyHandlers.ofString());

if (res.statusCode() != 200)
throw new RuntimeException("HTTP " + res.statusCode());
return res.body();
}

public static String createTodo(String title, int userId) throws Exception {
String json = String.format(
"{\"title\":\"%s\",\"completed\":false,\"userId\":%d}", title, userId);

HttpResponse<String> res = client.send(
HttpRequest.newBuilder()
.uri(URI.create(BASE + "/todos"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build(),
HttpResponse.BodyHandlers.ofString());

System.out.println("Created: HTTP " + res.statusCode());
return res.body();
}

public static void deleteTodo(int id) throws Exception {
HttpResponse<Void> res = client.send(
HttpRequest.newBuilder()
.uri(URI.create(BASE + "/todos/" + id))
.DELETE().build(),
HttpResponse.BodyHandlers.discarding());
System.out.println("Deleted: HTTP " + res.statusCode());
}

public static void main(String[] args) throws Exception {
System.out.println("GET todo #1:\n" + getTodo(1));
System.out.println("CREATE:\n" + createTodo("Study Java", 1));
deleteTodo(1);
System.out.println("Done.");
}
}
tip

Pro tip: Use HttpClient (Java 11+) for all new HTTP code:

  • Cleaner fluent API
  • HTTP/2 built-in
  • Native async support via CompletableFuture
  • Better timeout/redirect handling

Use HttpURLConnection only for Java 8/9/10 compatibility. For complex production REST clients, consider OkHttp or Retrofit for retry logic, interceptors, and type-safe JSON parsing.