Javaのカレンダー | Advent Calendar 2021の15日目の記事です
※ 少し呑んでます
概要
Java の Stream と List(等) で1000件くらいのオブジェクトを扱ったときのヒープ(メモリ)の使用量がどのように変わるかを確認しました
結果は、Stream の方が List よりも 1/4 のヒープで動いてそうです。これだけでも、Stream を使うメリットを感じられるのではないでしょうか?
大量のデータを扱うようなシーンでは、Stream API よりも Spring Batch などの専用のフレームワークを利用すべしとあるので、あくまでも比較的件数が限られているものの用途に向いてそうです
比較したコード
コードは適当なオブジェクトを 1000回分生成してリストに詰める(Stream から List に変換)するものです。
Stream を使う場合
void useStream() {
IntStream.range(0, 1000).parallel().mapToObj(i -> create()).collect(Collectors.toList());
}
parallel() があってこそのこの結果で、parallel() がないと、 List の場合とほぼ変わらない、もしくはちょっと大きい結果になりました m(_ _)m
List を使う場合
void useList() {
List<Parson> l = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
l.add(create());
}
}
測定結果
測定には、以前の記事 Javaでヒープサイズ測定 JUnit5編 で使用した、quickperf を使いました
Stream を使う場合
[QUICK PERF] Measured heap allocation (test method thread): 137.34 Kilo bytes (140 640 bytes)
List を使う場合
[QUICK PERF] Measured heap allocation (test method thread): 510.02 Kilo bytes (522 264 bytes)
付録
テストコード全体
@QuickPerfTest
public class StreamVsListTest {
@MeasureHeapAllocation
@Test
void useStream() {
IntStream.range(0, 1000).parallel().mapToObj(i -> create()).collect(Collectors.toList());
}
@MeasureHeapAllocation
@Test
void useList() {
List<Parson> l = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
l.add(create());
}
}
@AllArgsConstructor
@Data
class Parson {
private String name;
private int age;
private String addr;
private String addr2;
}
Parson create() {
return new Parson(RandomStringUtils.randomAlphabetic(10), new Random().nextInt(), RandomStringUtils.randomAlphabetic(20), RandomStringUtils.randomAlphabetic(20));
}
}