ユーティリティクラスと static ファクトリーメソッド
インスタンス化できないユーティリティクラスを設計し、コンストラクターの代わりに static ファクトリーメソッドを公開します。
「ユーティリティクラスと static ファクトリーメソッド」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
ユーティリティクラスとstaticファクトリメソッド
ユーティリティクラスは、インスタンス状態を持たず、staticヘルパーメソッドを提供します。staticファクトリメソッドは、コンストラクタに代わる名前付きのメソッドで、可読性、キャッシュ、柔軟性を向上させます。
ユーティリティクラス
ユーティリティクラスにはインスタンス状態がなく、staticメソッドの入れ物として機能します。privateコンストラクタを宣言して、インスタンス化できないようにします。
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の標準ライブラリには、Collections、Arrays、Objects、Files、Paths、Mathなど、数多くのユーティリティクラスがあります。
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)staticファクトリメソッド
staticファクトリメソッドは、インスタンスを作成して返す、名前の付いたstaticメソッドです。説明的な名前を付けられるほか、キャッシュ済みのインスタンスやサブタイプのインスタンスを返したり、nullを返したりできます。
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)staticファクトリによるキャッシュ
staticファクトリはキャッシュ済みのインスタンスを返せるため、よく使う値に対する繰り返しの割り当てを避けられます(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)ファクトリとコンストラクタ:命名
staticファクトリメソッドでよく使われる命名規則:
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"; }
};
}
}staticファクトリによるBuilder
privateコンストラクタ、staticファクトリ、ネストした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()); // trueCollections API:staticファクトリ
Java 9以降では、List.of()、Set.of()、Map.of()が追加されました。これらは不変コレクションを作成するstaticファクトリメソッドです。
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")
);ファクトリメソッドを優先する場合
次のような場合は、コンストラクタよりstaticファクトリメソッドを優先します:
- 説明的な名前を付けたい場合
- ファクトリがキャッシュ済みのインスタンスやサブタイプのインスタンスを返す可能性がある場合
- 構築前に検証が必要な場合
- インスタンスの数(Singletonやプール)を制御したい場合
// 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理解度チェック
publicコンストラクタに対するstaticファクトリメソッドの主な利点は何ですか?
まとめ:ユーティリティクラスとstaticファクトリメソッド
重要なポイント:
- ユーティリティクラスは、privateコンストラクタを持つfinalクラスで、すべてのメソッドがstaticです
- staticファクトリメソッドは、コンストラクタに代わる名前付きのメソッドです
- よく使われる命名は、of、from、valueOf、getInstance、create、newInstanceです
- ファクトリはキャッシュ済みのインスタンスを返せます。Integer.valueOf(-128..127)を参照してください
- ファクトリは具体的な実装を隠したまま、サブタイプを返せます
- 複数のパラメータを使う複雑な構築には、ファクトリ内でBuilderを使用します
よくある質問
「ユーティリティクラスと static ファクトリーメソッド」レッスンは無料ですか?
はい。「ユーティリティクラスと static ファクトリーメソッド」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「ユーティリティクラスと static ファクトリーメソッド」で何を学びますか?
インスタンス化できないユーティリティクラスを設計し、コンストラクターの代わりに static ファクトリーメソッドを公開します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「ユーティリティクラスと static ファクトリーメソッド」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- メソッドオーバーロードの規則
- 可変長引数パラメーター
- static フィールドと定数
- ユーティリティクラスと static ファクトリーメソッド