Builder

Many Optional Parameters

When a class has many fields, especially optional ones, constructors like new Pizza("L", true, false, true, null, 2) are unreadable. A Builder sets fields by name and builds an immutable object at the end, with validation in one place.

Example

import java.util.*;

public class Main {
    public static void main(String[] args) {
        HttpRequest req = HttpRequest.builder("https://api.shop.in/orders")
                .method("POST")
                .header("Authorization", "Bearer abc123")
                .header("Content-Type", "application/json")
                .body("{\"sku\":\"PHN-01\"}")
                .timeoutSeconds(5)
                .build();
        System.out.println(req);

        try {
            HttpRequest.builder("").build();
        } catch (IllegalStateException e) {
            System.out.println("Validation: " + e.getMessage());
        }
    }
}

final class HttpRequest {
    private final String url, method, body;
    private final Map<String, String> headers;
    private final int timeoutSeconds;

    private HttpRequest(Builder b) {
        url = b.url; method = b.method; body = b.body;
        headers = Collections.unmodifiableMap(new LinkedHashMap<>(b.headers));
        timeoutSeconds = b.timeoutSeconds;
    }

    static Builder builder(String url) { return new Builder(url); }

    public String toString() {
        return method + " " + url + " headers=" + headers + " body=" + body + " timeout=" + timeoutSeconds + "s";
    }

    static final class Builder {
        private final String url;
        private String method = "GET", body = "";
        private final Map<String, String> headers = new LinkedHashMap<>();
        private int timeoutSeconds = 30;

        private Builder(String url) { this.url = url; }
        Builder method(String m) { this.method = m; return this; }
        Builder header(String k, String v) { headers.put(k, v); return this; }
        Builder body(String b) { this.body = b; return this; }
        Builder timeoutSeconds(int t) { this.timeoutSeconds = t; return this; }

        HttpRequest build() {
            if (url.isBlank()) throw new IllegalStateException("url is required");
            return new HttpRequest(this);
        }
    }
}

Output

POST https://api.shop.in/orders headers={Authorization=Bearer abc123, Content-Type=application/json} body={"sku":"PHN-01"} timeout=5s
Validation: url is required

In the JDK and Libraries

  • StringBuilder, HttpRequest.newBuilder() (java.net.http), Thread.ofVirtual(), Stream.builder().
  • Lombok @Builder generates all of the above from one annotation.
  • Spring: ResponseEntity.ok().header(...).body(...), WebClient.builder(), UriComponentsBuilder.