Java SE8ではforEachよりもStramが早い!!
既に一週間以上経ち、かなり今更感がありますが、
JJUG ナイト・セミナー 「Java エンジニアのためのJava(再)入門」 6/20(木)開催 | 日本Javaユーザーグループ
に参加してきました。
その際に、@yoshioteradaさんに勧められたのをきっかけに、私もJavaやJavaScriptなど、自分の学んだことをブログにまとめようと思い、このページを作りました。
週に一回くらいは、何かしらの情報をアップしていこうと思います。
#このブログの使い方についても、少しずつマスターしていこう・・・
早速ですが、今日の話題は、JJUG ナイト・セミナー 「Java エンジニアのためのJava(再)入門」 6/20(木)開催 | 日本Javaユーザーグループで@cero_tさんからお話いただいた、from old Java to modern Javaの内容についてです。
内容的な部分は、最近Java7を使っている私としては、Java6の部分までは、特に知らないことろもなく、「ふんふん。そうだよねぇ。。。」と言う感じで聞いていました。
#いや、年齢的な意味でも、Java5でのジェネリクスの導入による衝撃なんかは知らないんだけどさ...^^;
知らないところが出てきたのは、Java7から。。。
以下、知らなかった点
・Java SE7からObjects.HashというAPIができた
・Java SE7では、Files.readAllLinesというAPIがある
の二点。(あれ?APIだけじゃね?話は文法的なところがメインじゃなかったっけ?)
そして、最も気になった部分があったのは、Java SE8の部分が終わって、質問タイムの時!
「新しい文法を古いものになれた人にどう進めればいいんでしょう?」
と言う質問に対する@skrbさんの答えの中に、
「Streamを使うだけでforEachよりも格段に早いんです!」
って話がありました。
そんなことは全く知らない私は「え?そうなの?(ぽかーん」状態。。。
ということで、前置きが長くなりましたが、本日はここを検証します。
Streamをてっとり早く検証しようと思って、以下(ページ下部に準備)のようなソースコードを準備しました。
#ほぼ@cero_tさんがスライドにあげているもののパクリ^^;
実行した結果がこちら
for Loop Time is :5612
stream Loop Time is :3335
Parallel stream Loop Time is :4510
#あ、結果の単位はすべて[msec]です!
う。。。うん。確かに、Streamを使った方がforEachより早い!
並列化した方が遅いのは、処理内容が簡単すぎて、並列化のオーバヘッドの方が大きくなっただけだろうか?
ここは少し疑問に思うところ。。。時間があるときに、見てみようと思います。
というか、そもそも、なんでStreamを使うと早いかという部分も検証すべきなんですが、今週は忙しかったので、ごめんなさい。。。
ちゃんと調べておきます。
ということで、今回は、StreamがforEachよりも早いよ!と言うことを確認してみました。
実際、確かに早かったので、forEachではなく、Streamをじゃんじゃん使っていきましょう!(Lambda普及的な意味でも^^)
次回は、Java SE8で新しくなったJava VM(Nashorn)JavaScriptエンジン(Nashorn)に関して、書いてみようと思います。
(裏話)
実は、このソースコード、実際に動かしてみると、最初はStreamの方がかなり遅いという結果がでていました。
おかしいなぁ。。。と思いつつ、一日放置して、その後、ソースコードを書き直してみた結果がこれ。
うーん。。。たぶんどっかで書き間違えしたんだろうな。。。
//実行したコード package com.iboy; import com.iboy.entity.Record; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; public class Main { public static int LIST_SIZE = 10000000; public static int SEED = 100000; /** * テストデータの作成 * @return */ private List<Record> createTestData() { Random random = new Random(SEED); List<Record> list = new ArrayList<>(); for (int i=0; i < LIST_SIZE; i++) { int tmp = random.nextInt(); Record tmpRecode = new Record(tmp); list.add(tmpRecode); } return list; } /** * 通常のforEachを用いた処理 * @param data filter&sort対象のデータ */ private void doForEachProcess(List<Record> data) { List<Record> list3 = new ArrayList<>(data); long currentTime = System.currentTimeMillis(); List<Record> tmpList = new ArrayList<>(); for (Record record : list3) { if (record.getScore() % 2 == 0) { tmpList.add(record); } } Comparator<Record> comparator = new Comparator<Record>() { @Override public int compare(Record o1, Record o2) { if (o1.getScore() < o2.getScore()) { return -1; } else if (o1.getScore() == o2.getScore()) { return 0; } return 1; } }; Collections.sort(tmpList, comparator); long endTime = System.currentTimeMillis(); System.out.println("for Loop Time is :" + (endTime - currentTime)); } /** * Streamを用いた処理 * @param data */ private void doStreamProcess(List<Record> data) { List<Record> list = new ArrayList<>(data); long currentTime = System.currentTimeMillis(); list.stream().filter(record -> record.getScore() % 2 == 0) .sorted((o1, o2) -> { if (o1.getScore() < o2.getScore()) { return -1; } else if (o1.getScore() == o2.getScore()) { return 0; } return 1; }) .collect(Collectors.toList()); long endStreamTime = System.currentTimeMillis(); System.out.println("stream Loop Time is :" + (endStreamTime - currentTime)); } /** * ParallelStreamを用いた処理 * @param data */ private void doParallelStreamProcess(List<Record> data) { List<Record> list = new ArrayList<>(data); long currentTime = System.currentTimeMillis(); List<Record> sorted = list.parallelStream().filter(record -> record.getScore() % 2 == 0) .sorted((o1, o2) -> { if (o1.getScore() < o2.getScore()) { return -1; } else if (o1.getScore() == o2.getScore()) { return 0; } return 1; }).collect(Collectors.toList()); long endParallelStreamTime = System.currentTimeMillis(); System.out.println("Parallel stream Loop Time is :" + (endParallelStreamTime - currentTime)); } public static void main(String[] args) { Main main = new Main(); List<Record> list = main.createTestData(); //Do forEach process main.doForEachProcess(list); //Do Stream process main.doStreamProcess(list); //Do parallel Stream process main.doParallelStreamProcess(list); } }