Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

JavaのRecordでは配列を使わないほうが良いという話

配列使うとmutableになるから使うべきではない、というのに加えて。生成される hashCode()equals(Object), toString() が配列を考慮しない実装になっているため、JavaのRecordでは配列を使わないほうが良いようです。

検証コード

生成される hashCode()equals(Object) の挙動を検証するコードです。

gist.github.com

なぜこうなるのか

ObjectMethods クラスによって生成されるコードを見ると、 Arrays.hashCode(int[]) ではなくint[].hashCode()が、Arrays.equals(int[], int[]) ではなく int[].equals(Object) が使われているようです。これは考慮漏れというわけではなく、ObjectMethodsクラスのjavadocに明記されている仕様です。core-libs-devメーリスに質問を投げて確認しました

実際の実装はObjectMethodsクラスのコードを読むか、以下の記事を参照ください。

alidg.me

望ましい対策

Recordでは配列の代わりに不変コレクションを利用するのが望ましいと思われます。Java 9からimmutable listを作るfactory methodが導入されています。また不変であることを型として示したいならば、GuavaのImmutableListを使う手もあります。

Recordクラスがmutableになるリスクを受容した上で配列を使う場合は、hashCode()equals(Object), toString() を自動生成に頼るのではなくハードコードすることで、この問題を回避可能です。大抵のIDEにはこれらのコードを自動的に生成する機能が備わっているので、利用すると良いでしょう。