public record Foo(String a, int b) {}
このようなレコードクラスがあったとき、このコンストラクタを隠すことはできません。
ただ、
public record Foo(String a, int b) { public static final List<Foo> foos; static { List<Foo> list = new ArrayList<>(); for (var x : ...) list.add(new Foo(x.a, x.b)); foos = Collections.unmodifiableList(list); } }
のように固定の数のFooのインスタンスを作りたいとき、レコードクラスのコンストラクタは公開されています。ではどうするか。
結論
このようになりました。
public record Foo(@Deprecated __private__ _unused_, String a, int b) { private record __private__() { static final __priavte__ instance = new __priavte__(); } public static final List<Foo> foos; static { List<Foo> list = new ArrayList<>(); for (var x : ...) list.add(new Foo(__private__.instance, x.a, x.b)); foos = Collections.unmodifiableList(list); } }
Foo.__private__
クラスは外部からアクセス不能であり、結果としてFooクラスのコンストラクタを外部から実行することはできません。
これでコンパイル時チェックが可能になりました。_unused_
というゴミプロパティが残るのが唯一の欠点ですが、実用上問題ありません。
追記
null
を渡せば良いことを忘れていました。つまりこれはコンパイルエラーになりません。
new Foo(null, "a", 1);
/(^o^)\
何とかするとしても
public record Foo(@org.jetbrains.annotations.NotNull @Deprecated __private__ _unused_, String a, int b) { ... }
ってやるくらいですかね…
まあ、仮にコンストラクタをprivateにできたとしてもリフレクションで強引に呼び出すことは依然として可能なわけで。 上記のようにしておけば、「間違って呼び出してしまう」というコードを書いてしまう可能性を、ほぼゼロにはできると思います。