まとめ
Java value class と record の違いを知りたい場合、ポイントは「どちらが短く書けるか」ではありません。record はデータキャリアを簡潔に書く機能ですが、通常の record は依然としてアイデンティティを持つオブジェクトです。Project Valhalla の value class は、アイデンティティのない値オブジェクトを Java に入れようとしています。
この違いは ==、同期、メモリレイアウト、JVM の最適化余地に影響します。実務では「この型にライフサイクルや個体性が必要か。それとも小さく不変な値として扱いたいだけか」を見るのが判断軸になります。
目次
この記事の内容
Java record が解決すること
record は、DTO や読み取り用データキャリアの定型コードを減らします。
public record Point(int x, int y) {}
コンパイラがコンストラクタ、アクセサ、equals、hashCode、toString を用意してくれるため、API レスポンス、内部コマンド、設定値、テストデータに便利です。
ただし record は通常のオブジェクトです。同じ値でも別インスタンスなら == は false になり得ます。
Point a = new Point(1, 2);
Point b = new Point(1, 2);
System.out.println(a.equals(b)); // true
System.out.println(a == b); // false
Project Valhalla の value class が変えること
value class は構文の短縮ではなく、Java のオブジェクトモデルと性能モデルに関わる変更です。JEP 401 の方向性は次の例で理解できます。
value record Point(int x, int y) {}
Point p = new Point(17, 3);
Objects.hasIdentity(p); // false
new Point(17, 3) == p; // true
ここで重要なのは、Objects.hasIdentity(p) が false になる点です。焦点はヒープ上の特定の個体ではなく、x=17、y=3 という値そのものです。
最大の違いはアイデンティティ
record:
- アイデンティティを持つ通常のオブジェクト
- 主目的は構文と定型コードの削減
- equals/hashCode/toString を自動生成
- 通常の heap object として扱われる
value class:
- アイデンティティのない値オブジェクト
- 主目的は JVM object model と性能モデルの改善
- 同じ値なら同じ値として扱える
- flattening / scalarization などの最適化余地がある
アイデンティティがないことは利点ですが、同期対象やアイデンティティベースのキャッシュには向きません。
性能重視コードで重要な理由
Java では小さな値を表す型が頻繁に登場します。
Money
Point
Range
UserId
OrderId
EventTime
MetricPoint
これらはドメインの意味をよく表しますが、大量に作ると割り当て、参照追跡、GC の負担が問題になります。
従来の Point[]:
-> reference
-> heap object Point
-> x, y
value class が安定した後に期待される方向:
-> x, y の値をより直接配置できる可能性
ただし、実際の効果は JVM 実装とコードの形に依存します。ベンチマークなしに性能改善を前提にするのは危険です。
実務で向く場面
value class Money {
private long cents;
public Money(long cents) {
this.cents = cents;
}
public long cents() {
return cents;
}
}
long cents だけなら速いかもしれませんが意味が弱くなります。Money として表現でき、かつ実行時コストを抑えられるなら、ドメインモデルと性能の妥協を減らせます。
- 金額、座標、範囲、時間間隔
- 注文 ID、ユーザー ID、トレース ID
- イベント、ログ、メトリクスの小さな値型
- ベクトル検索や並べ替えで使う小さな数値データ
注意点とチェックリスト
value class は record の上位互換ではありません。次の点を確認します。
- オブジェクトの個体性、ライフサイクル、可変状態が必要なら通常の class が向く
synchronized、ロックキー、アイデンティティベースのキャッシュに使うなら不向き- 小さく、不変で、フィールド値だけで意味が決まるなら候補になる
- JEP 401 はプレビューなので、本番採用は仕様安定後に検証する
結論
record は Java コードを簡潔にする機能です。value class は Java のオブジェクトモデルと性能モデルに踏み込む機能です。見た目は似ても、目的はかなり違います。
長く Java を使っていると、きれいなドメインモデルと性能の間で悩むことがあります。value class はその妥協を減らす可能性があります。ただし、まだプレビュー段階であり、公式仕様と実測を確認しながら学ぶのが現実的です。
参考文献
- OpenJDK Project Valhalla
- JEP 401: Value Classes and Objects (Preview)
- JEP 402: Enhanced Primitive Boxing (Preview)