Effective Java privateのコンストラクタでインスタンス化不可能を強制する


Effective Javaの独自解釈です。
第3版の項目4について、自分なりにコード書いたりして解釈してみました。

結論

staticメンバしか持たないクラスには、実行時例外を出すprivateコンストラクタを用意しよう。

説明

例えば共通の処理だけを集めたユーティリティクラス(以下、Utilクラス)はstaticメソッド、static変数のみを持ち、インスタンス化を前提としていない。

一般にpublicなUtilクラスは、コンストラクタを定義しないとpublicなデフォルトコンストラクタが用意されるため、外部のクラスで無駄にインスタンス化されてしまう懸念が生じる。

明示的にprivateコンストラクタを定義することで、Utilクラス外でのコンストラクタ呼び出しを防ぐことができる。
また、コンストラクタに例外出力処理を入れることで、Utilクラス内でのコンストラクタ呼び出しをエラーとすることができる。

※Utilクラスそもそもいらない論はここでは無視。

コンストラクタ定義なしコード(ダメな例)

Utilクラス

public class SampleUtil {

    public static final String HOGE = "hoge";

    public static String fugaMethod() {
        return "fuga";
    }
}

呼び出し側クラス

public class SampleService {

    public String sampleMethod() {
        // 無駄にインスタンス化
        SampleUtil sampleUtil = new SampleUtil();
        return sampleUtil.fugaMethod();
    }
}

呼び出し側クラスでインスタンスを作っています。fugaMethod()はstaticメソッドなので、インスタンス化するのは無駄です。

privateコンストラクタ定義ありコード(良い例)

Utilクラス

public class SampleUtil {

    // privateかつ実行時例外を出力するコンストラクタを定義
    private SampleUtil() {
        throw new IllegalStateException("Util instance construction is not allowed.");
    }

    public static final String HOGE = "hoge";

    public static String fugaMethod() {
        return "fuga";
    }

}

呼び出し側クラス

public class SampleService {

    public String sampleMethod() {
        return SampleUtil.fugaMethod();
    }
}

コンストラクタがprivateなので、別のクラスではそもそもインスタンス化できません。

また、仮にUtilクラス内でコンストラクタが呼ばれたとしても、例外が出力されるためインスタンスが作られることはありません。コンストラクタを呼ぶようなコードが書かれている場合、それはプログラミングエラーなので、実行時例外を出すようにしましょう。

※コンパイルは通るので、プログラミングエラー自体を防ぐことはできません。