9.61: ボクシングされた基本データよりも基本データ型を選ぶ
結論
可能な限り プリミティブ型(int, long, double など)を使い、ボクシングされたラッパ型(Integer, Long, Double 等)を避ける。
理由は主に
(1)性能(オートボクシング/アンボクシングのコスト・ガベージ発生)、
(2)メモリ(ラッパーはオブジェクトなので大きい)、
(3)安全性(null のアンボクシングで NullPointerException が出る)、
(4)比較の誤解(== と参照等価)
──これらがバグや効率低下の原因になるため。
※ただし generics/コレクションの要件や API 境界でどうしてもオブジェクトが必要な場合は仕方ない(そのときは意図を明確に)。
良い例
プリミティブを使って安全かつ効率的に書く例。配列・プリミティブストリームを活用。
// 1) 純粋な数値ループはプリミティブで
long sum(long[] values) {
long s = 0L;
for (long v : values) {
s += v;
}
return s;
}
// 2) Java 8+ のプリミティブストリームを使う(ボクシングを避ける)
import java.util.stream.IntStream;
int sumRange(int n) {
// IntStream.rangeClosed はプリミティブ int を扱う -> ボクシング不要
return IntStream.rangeClosed(1, n).sum();
}
ポイント:
- ループ内やホットパスでは必ずプリミティブを使う(オートボクシングでオブジェクトが大量に生成されるのを避ける)
- コレクションを使う必要があるなら、可能な限りプリミティブ向けAPI(
IntStream/LongStream)やサードパーティのプリミティブコレクションを検討する
悪い例
ボクシングによる落とし穴(性能・バグ)の典型。
// NG: tight loop で List<Integer> を使うと大量のオブジェクトが生まれる
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
list.add(i); // autoboxing: int -> Integer, 1_000_000 個の Integer を割当て
}
long sum = 0L;
for (Integer x : list) {
sum += x; // unboxing: Integer -> int(さらに毎回オーバーヘッド)
}
// NG: null をアンボクシングして NPE
Integer maybeNull = null;
int primitive = maybeNull; // NullPointerException
// NG: == による誤った比較(参照等価と値等価の混同)
Integer a = 128;
Integer b = 128;
System.out.println(a == b); // false(キャッシュ外の値は別オブジェクト)
System.out.println(a.equals(b)); // true(値は等しい)
問題点:
- ホットパスでのオートボクシングは CPU とメモリを浪費する(ガベージ生成、キャッシュ負荷)
-
Integer等をnullにすることで、意図せずNullPointerExceptionが発生する -
==とequals()の混同でロジックのバグが生まれる(キャッシュ範囲によって結果が変わる)
まとめ
-
ホットパス/大量データはプリミティブを使う:
ループ、集計、数値配列等はint/long/doubleで。
-
API 境界ではラッパーが必要な場合がある:
ジェネリクスやコレクション(List<T>)ではオブジェクト型が必須。
ただし内部処理はプリミティブで行い、ボクシングは境界で最小化する。
-
プリミティブ向け API を使う:
IntStream/LongStream/DoubleStream、Arraysのプリミティブ overload を活用。
-
null をアンボクシングしない:
ラッパーを使うなら null の可能性を設計で排除するかOptionalInt等のプリミティブ Optional を検討する。
-
比較は equals を使う:
ラッパー同士の比較で==を使わない(参照等価に注意)。
-
大規模コレクションではプリミティブ専門ライブラリを検討:
memory- and GC-sensitive なケースでは fastutil / Trove など(プロジェクトポリシーに合わせて)。
-
測定して判断する:
パフォーマンス疑問があるならベンチマーク(JMH)で確かめる。
見積りだけで最適化しない。