For Java 11 or later, set a ProxySelector on the client builder. This leaves whole-JVM proxy properties alone:

import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class ProxyExample {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder()
            .proxy(ProxySelector.of(
                new InetSocketAddress("203.0.113.10", 8080)))
            .connectTimeout(Duration.ofSeconds(5))
            .build();

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://example.com/"))
            .timeout(Duration.ofSeconds(15))
            .GET()
            .build();

        HttpResponse<String> response = client.send(
            request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode());
        System.out.println(response.body());
    }
}

Replace the documentation endpoint with your HTTP proxy; the HTTP proxy list provides candidates to test. ProxySelector.of takes a socket address: use the host without an http:// prefix and supply the port separately. It selects an HTTP proxy, not SOCKS based on the port number. The request URI remains the real destination.

HTTPS can travel through this HTTP proxy using a tunnel. There is no need to downgrade the destination, and the setup does not imply TLS support on the proxy listener itself.

The client builder's connection timeout applies when establishing a connection; the request has its own timeout. Keep both visible because a request can reuse an existing connection. A network, authentication or tunnel exception can precede any destination response, while a returned error status need not throw an exception.

Reuse the client for requests with the same routing policy so the application can benefit from its connection management.

Allakkat attuumassuteqartut