暗黙的なボクシング処理
Javaの int と Integer は殆ど同じような感覚で使ってると思いますが、
int から、Integer にする時は、boxing
Integer から、int になる時は、unboxing という処理が暗黙的に行われています。
微々たるものですが、やはり処理コストがかかっているので、知識として知っておくと良いかと思います。
処理速度比較
例えば、Integerを使ったジェネリクスを扱う時に、ループ処理などでは、感覚的にintで扱う事はよくありますが。
1千万の要素をもつハッシュマップから、
boxingが発生しない場合と、int -> Integerでboxing処理が発生する場合で、
どのくらい速度差があるか測定してみました。
テスト用のマップ作成
// 10,000,000要素のマップを作成
Map<Integer, Integer> map = IntStream.rangeClosed(1, 10000000)
.boxed()
.collect(Collectors.toMap(i -> i, i -> i));
Integerを使った場合
Integer[] keys = map.keySet().toArray(new Integer[0]);
for (int i = 0; i < 10; i++) {
long processStart = System.nanoTime(); // 測定開始
long sum = 0;
for (Integer _integer : keys) {
sum += map.get(_integer);
}
long processEnd = System.nanoTime(); // 測定終了
System.out.println(String.format("PROCESS_TIME: %d[ms]", (processEnd - processStart) / 1000000));
}
PROCESS_TIME: 98[ms]
PROCESS_TIME: 77[ms]
PROCESS_TIME: 72[ms]
PROCESS_TIME: 111[ms]
PROCESS_TIME: 71[ms]
PROCESS_TIME: 65[ms]
PROCESS_TIME: 97[ms]
PROCESS_TIME: 66[ms]
PROCESS_TIME: 66[ms]
PROCESS_TIME: 96[ms]
intを使った場合
int[] keys = map.keySet().stream().mapToInt(i -> i).toArray();
for (int i = 0; i < 10; i++) {
long processStart = System.nanoTime(); // 測定開始
long sum = 0;
for (int _int : keys) {
sum += map.get(_int); // int -> Integerへのboxing処理が入っている
}
long processEnd = System.nanoTime(); // 測定終了
System.out.println(String.format("PROCESS_TIME: %d[ms]", (processEnd - processStart) / 1000000));
}
PROCESS_TIME: 265[ms]
PROCESS_TIME: 194[ms]
PROCESS_TIME: 210[ms]
PROCESS_TIME: 198[ms]
PROCESS_TIME: 211[ms]
PROCESS_TIME: 188[ms]
PROCESS_TIME: 174[ms]
PROCESS_TIME: 155[ms]
PROCESS_TIME: 205[ms]
PROCESS_TIME: 202[ms]
Map::get が求めるのは参照型なので、
int を渡した場合、暗黙的にboxing処理が発生しています。
V get(Object key);
Integer と int どちらを使うほうが良いのか?
速度差は2倍くらい違うみたいですが、
正直、1千万回のループでもこのくらいの差なので〜、・・・どちらでもいい気がします。
ちなみに、速度差測定した時に使用したJavaバージョンは、8と10で特に大差ありませんでした。