JavaBeanとPOJOはどう違い、どちらを使うべきか

Javaの歴史において「JavaBean」と「POJO」はよく混同されますが、この二者は設計意図も使用目的も明確に異なります。

本記事では、両者の違いを構造・責務・設計方針の観点から整理し、レビュー時にどちらを選択すべきかを判断できるようにします。

JavaBeanとは何か?

JavaBeanとは、もともとIDEやツールから操作しやすいよう設計されたクラスの規約です。以下のような特徴を持ちます。

JavaBeanの要件

  • デフォルトコンストラクタ(引数なし)を持つ
  • privateなフィールドと、そのためのpublicなgetter/setterを持つ
  • Serializableインターフェースを実装していることが多い
JavaBeanの例
public class User {
    private String name;
    private int age;

    public User() {} // デフォルトコンストラクタ

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}
JavaBeanの歴史的背景

JavaBeanはEclipseなどのIDEや、JSP・JSFなどのテンプレートエンジンでプロパティアクセスを自動化するために発展した構造です。

POJOとは何か?

POJO(Plain Old Java Object)は、JavaBeanのようなツール依存の規約とは無関係に、“プレーンなJavaオブジェクト”として構造を保つクラスを指します。

POJOの例(publicフィールドで直接参照)
public class Product {
    public final String name;
    public final int price;

    public Product(String name, int price) {
        this.name = name;
        this.price = price;
    }
}
  • getter/setterが不要なケースもある
  • 不変性(final)を保てる
  • 設計意図が明確で、責務を小さく保ちやすい

ただし、「getterを定義してはいけない」という意味ではありません。

getterは設計判断で“必要なら定義する”

POJOは自由な設計を許容する構造です。カプセル化やアクセサ制御を意図するなら、getterを定義してもPOJOの範囲内です。

POJOでもgetterを持つ例
public class Person {
    private final String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

このように、POJOは「getterが不要」というよりも、設計意図に従ってgetterを使い分けられる構造であることが本質です。

POJO設計における本質:不変性をどう扱うか?

POJOにおいて getter の有無を議論する際、焦点は「不変性をどう担保するか」にあります。

不変性(immutability)とは

インスタンス生成後に状態が一切変わらない性質のこと。副作用の排除や安全な共有のために重要な設計特性です。

設計判断の分岐

状態の扱い方 推奨される構造例
完全に変更させたくない public final + コンストラクタのみ
外部変更を制限しつつ読み取り可能 private final + getter
状態変化を許容したい private + getter/setter

このように、getterを定義するかどうかは「不変性を維持しつつ何を外部に公開するか」によって決まります。

getterの要否は設計次第

getterが「不要」なのではなく、「必要に応じて選べる」ことがPOJOの柔軟性です。不変性の設計方針に従って判断してください。

レビュー時は「getterがあるかどうか」ではなく、
「このクラスは本来、不変であるべき構造か?」「状態変更を許すべきか?」を確認することが重要です。

JavaBeanとPOJOの比較

比較項目 JavaBean POJO
主目的 IDE・テンプレート連携 プレーンな設計の保持
getter/setter 必須 任意(不要なことも多い)
デフォルトコンストラクタ 必須 不要
不変性の担保 困難 容易(final利用)
ツール依存 あり(特にDI・テンプレート) なし(設計意図に依存)

設計上の適切な使い分け

POJOを使うべきケース

  • 不変な構造でドメイン値を表現したい
  • 状態変化を持たず、値としての意味を強調したい
  • 設計上の意図(例:金額、位置、識別子など)をコードに明示したい

JavaBeanを使わざるを得ないケース

  • フレームワークがgetter/setterを前提としている(例:JSP, JSF, 一部のORM)
  • ツールがデフォルトコンストラクタを要求する
  • 外部ライブラリと互換性を保つために規約を合わせる必要がある
JavaBeanを“設計”として選ばない

JavaBeanは「設計パターン」ではなく「道具の都合に合わせた規約」であり、明確な理由がない限りPOJOを優先すべきです。

よくあるレビュー観点:JavaBean的な構造が混入していないか?

チェックリスト

レビュー観点

getter/setterを理由なく備えたクラスには、JavaBean化による責務逸脱がないかを確認する。

recordとの比較補足

Java14以降、record が追加されたことで、POJOとrecordの棲み分けもレビュー上重要になっています。

特徴
POJO 自由度高、設計に従って定義できる
record 完全に不変なデータ容器

POJOは設計意図の反映に向く。recordは構造だけを表現したい場合に向く。

まとめ:JavaBeanは“技術的都合”、POJOは“設計的都合”

レビューの原則として、次のように捉えると判断しやすくなります。

  • POJOを選ぶ → 設計上の意図があり、それをコードに表現する
  • JavaBeanを選ぶ → 道具やフレームワークの制約を考慮して妥協する

JavaBeanはかつて多用されましたが、現在のJavaではrecordやPOJOによる責務分離の方が設計的に適しています。