0Pricing
Java Academy · 강의

유틸리티 클래스와 정적 팩터리 메서드

인스턴스화할 수 없는 유틸리티 클래스를 설계하고 생성자의 대안으로 정적 팩터리 메서드를 제공합니다.

유틸리티 클래스와 정적 팩터리 메서드은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

유틸리티 클래스와 정적 팩터리 메서드

유틸리티 클래스는 인스턴스 상태 없이 정적 도우미 메서드를 제공합니다. 정적 팩터리 메서드는 생성자를 대신하는 이름 있는 메서드로, 가독성·캐싱·유연성을 높여 줍니다.

유틸리티 클래스

유틸리티 클래스에는 인스턴스 상태가 없으며 정적 메서드를 담는 컨테이너입니다. 비공개 생성자를 선언하여 인스턴스화할 수 없게 만드세요.

final class StringUtils {
    // Private constructor prevents instantiation
    private StringUtils() {
        throw new UnsupportedOperationException("Utility class");
    }

    public static boolean isBlank(String s) {
        return s == null || s.strip().isEmpty();
    }

    public static String capitalize(String s) {
        if (isBlank(s)) return s;
        return Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase();
    }
}

System.out.println(StringUtils.isBlank("  ")); // true
System.out.println(StringUtils.capitalize("hELLO")); // Hello

표준 라이브러리 유틸리티 클래스

Java 표준 라이브러리에는 유틸리티 클래스가 매우 많습니다: 컬렉션, 배열, 객체, 파일, 경로, 수학 관련 클래스입니다.

import java.util.*;

List<Integer> nums = new ArrayList<>(Arrays.asList(5, 2, 8, 1, 9, 3));

Collections.sort(nums);
System.out.println(nums); // [1, 2, 3, 5, 8, 9]

System.out.println(Collections.min(nums)); // 1
System.out.println(Collections.max(nums)); // 9

Collections.shuffle(nums); // random order

int[] arr = {3, 1, 4, 1, 5};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // [1, 1, 3, 4, 5]
System.out.println(Arrays.binarySearch(arr, 4)); // 3 (index)

정적 팩터리 메서드

정적 팩터리 메서드는 인스턴스를 생성하고 반환하는 이름 있는 정적 메서드입니다. 장점으로는 설명적인 이름, 캐시된 인스턴스나 하위 형식 인스턴스 반환, 널 반환 등이 있습니다.

class Connection {
    private final String host;
    private final int port;
    private final boolean ssl;

    private Connection(String host, int port, boolean ssl) {
        this.host = host; this.port = port; this.ssl = ssl;
    }

    // Named factory methods — more expressive than constructors
    public static Connection plain(String host) {
        return new Connection(host, 80, false);
    }
    public static Connection secure(String host) {
        return new Connection(host, 443, true);
    }
}
Connection c = Connection.secure("api.example.com");
// Much clearer than: new Connection("api.example.com", 443, true)

정적 팩터리를 사용한 캐싱

정적 팩터리는 캐시된 인스턴스를 반환하여 자주 사용되는 값에 대한 반복적인 할당을 피할 수 있습니다(예를 들어 Integer.valueOf는 -128부터 127까지의 값에 대해 이렇게 동작합니다).

class Color {
    private static final Map<String, Color> CACHE = new HashMap<>();

    public final int r, g, b;

    private Color(int r, int g, int b) {
        this.r = r; this.g = g; this.b = b;
    }

    public static Color of(int r, int g, int b) {
        String key = r + "," + g + "," + b;
        return CACHE.computeIfAbsent(key, k -> new Color(r, g, b));
    }

    public static final Color RED   = of(255, 0, 0);
    public static final Color GREEN = of(0, 255, 0);
    public static final Color BLUE  = of(0, 0, 255);
}
System.out.println(Color.of(255,0,0) == Color.RED); // true (cached)

팩터리와 생성자: 이름 지정

정적 팩터리 메서드에 사용하는 일반적인 이름 규칙은 다음과 같습니다:

  • of — 여러 값을 묶는 팩터리
  • from — 변환 팩터리
  • valueOf — 변환 팩터리(이전 API)
  • getInstance — 싱글턴
  • create/newInstance — 새 객체
  • get — 유연한 용도의 메서드
// Java API examples:
Optional.of(value)               // of
LocalDate.from(temporal)         // from
Integer.valueOf(42)              // valueOf
Calendar.getInstance()           // getInstance
Array.newInstance(type, length)  // newInstance

// Your own:
HttpRequest.post("https://api.example.com/users")
ApiResponse.error(404, "Not found")
Payment.creditCard("4242...", 9999, "USD")

하위 형식 반환

팩터리 메서드는 선언된 반환 형식이 인터페이스인 경우에도 하위 형식을 반환할 수 있습니다. 호출자는 구체적인 구현과 분리됩니다.

interface Validator<T> {
    boolean validate(T value);
    String errorMessage();
}

class EmailValidator implements Validator<String> {
    public boolean validate(String email) { return email.contains("@"); }
    public String errorMessage() { return "Invalid email address"; }
}

class Validators {
    // Returns interface type — hides implementation
    public static Validator<String> email() { return new EmailValidator(); }
    public static Validator<String> notBlank() {
        return new Validator<>() {
            public boolean validate(String s) { return s != null && !s.isBlank(); }
            public String errorMessage() { return "Value required"; }
        };
    }
}

정적 팩터리를 통한 Builder

복잡한 객체 생성을 위해 비공개 생성자, 정적 팩터리, 중첩 Builder를 결합합니다.

class EmailMessage {
    private final String to, subject, body;
    private final boolean html;

    private EmailMessage(Builder b) {
        this.to = b.to; this.subject = b.subject;
        this.body = b.body; this.html = b.html;
    }

    public static Builder builder(String to) { return new Builder(to); }

    public static class Builder {
        private final String to;
        private String subject = "", body = "";
        private boolean html = false;

        Builder(String to) { this.to = to; }
        public Builder subject(String s) { this.subject = s; return this; }
        public Builder body(String b) { this.body = b; return this; }
        public Builder html() { this.html = true; return this; }
        public EmailMessage build() { return new EmailMessage(this); }
    }
}
EmailMessage.builder("alice@co.com").subject("Welcome!").html().build();

팩터리 메서드에서의 검증

팩터리 메서드는 생성 전에 입력을 검증하는 데 매우 유용합니다. 상황을 설명하는 의미 있는 예외를 발생시키세요.

class PortNumber {
    private final int value;

    private PortNumber(int value) { this.value = value; }

    public static PortNumber of(int port) {
        if (port < 1 || port > 65535)
            throw new IllegalArgumentException(
                "Port must be 1-65535, got: " + port);
        return new PortNumber(port);
    }

    public static PortNumber http()  { return new PortNumber(80); }
    public static PortNumber https() { return new PortNumber(443); }

    public int value() { return value; }
    public boolean isPrivileged() { return value < 1024; }
}
System.out.println(PortNumber.https().isPrivileged()); // true

컬렉션 API: 정적 팩터리

Java 9부터 List.of(), Set.of(), Map.of()가 추가되었습니다. 이는 불변 컬렉션을 생성하는 정적 팩터리 메서드입니다.

import java.util.*;

List<String> fruits = List.of("Apple", "Banana", "Cherry");
Set<Integer> ids    = Set.of(1, 2, 3, 4, 5);
Map<String, Integer> ages = Map.of("Alice", 30, "Bob", 25);

// All are unmodifiable:
try {
    fruits.add("Durian"); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
    System.out.println("Cannot modify!");
}

// Map.entry and Map.ofEntries for > 10 entries
Map<String, String> config = Map.ofEntries(
    Map.entry("host", "localhost"),
    Map.entry("port", "8080")
);

팩터리 메서드를 우선 사용할 때

다음과 같은 경우 생성자보다 정적 팩터리 메서드를 우선 사용하세요:

  • 설명적인 이름을 사용하고 싶은 경우
  • 팩터리가 캐시된 인스턴스나 하위 형식 인스턴스를 반환할 수 있는 경우
  • 생성 전 검증이 필요한 경우
  • 인스턴스 수를 제어하고 싶은 경우(싱글턴, 풀)
// Constructor: hard to know what this means
new Complex(0.5, -1.2);

// Factory: clear meaning
Complex.fromPolar(1.3, Math.PI / 4); // polar form
Complex.rectangular(0.5, -1.2);      // rectangular form

// Constructor: no caching
new Boolean(true); // deprecated — creates new object!

// Factory: returns cached instance (Boolean.TRUE or FALSE)
Boolean.valueOf(true); // returns Boolean.TRUE singleton

빠른 확인

공개 생성자보다 정적 팩터리 메서드가 가지는 가장 큰 장점은 무엇입니까?

복습: 유틸리티 클래스와 정적 팩터리 메서드

핵심 정리:

  • 유틸리티 클래스: 비공개 생성자를 가진 최종 클래스이며 모든 메서드가 정적입니다
  • 정적 팩터리 메서드는 생성자를 대신하는 이름 있는 메서드입니다
  • 일반적인 이름: of, from, valueOf, getInstance, create, newInstance
  • 팩터리는 캐시된 인스턴스를 반환할 수 있습니다 — Integer.valueOf(-128..127) 참고
  • 팩터리는 구체적인 구현을 숨기면서 하위 형식을 반환할 수 있습니다
  • 여러 매개변수를 사용하는 복잡한 생성에는 팩터리 내부에서 빌더를 사용합니다

자주 묻는 질문

“유틸리티 클래스와 정적 팩터리 메서드” 강의는 무료인가요?

네 — “유틸리티 클래스와 정적 팩터리 메서드” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“유틸리티 클래스와 정적 팩터리 메서드”에서 뭘 배우나요?

인스턴스화할 수 없는 유틸리티 클래스를 설계하고 생성자의 대안으로 정적 팩터리 메서드를 제공합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Java Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“유틸리티 클래스와 정적 팩터리 메서드” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 메서드 오버로딩 규칙
  2. 가변 인자 매개변수
  3. 정적 필드와 상수
  4. 유틸리티 클래스와 정적 팩터리 메서드
← Java Academy(으)로 돌아가기