暇だったので、Java 8から追加されたjava.util.stream.IntStream
でちょっと遊んでみた。
ちなみに、IntStream
はinterface
であるが、ソースを見るとstaticメソッドの実装が書いてある。IntStream#of
とか。まぁそれは余談。
以下のようなソースで出力を見ていく。
import java.util.Arrays;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
int[] ary = { 5, 2, 8, 2, 9, 1, 3, 0, 5, 6, 4, 7, };
System.out.println("--------countTest");
countTest(ary);
System.out.println("--------sumTest");
sumTest(ary);
System.out.println("--------maxTest");
maxTest(ary);
System.out.println("--------minTest");
minTest(ary);
System.out.println("--------sortTest");
sortTest(ary);
System.out.println("--------1つのstreamで連続処理できるのかテスト");
test(ary);
System.out.println("--------パフォーマンスを計ってみる(sumを例に)");
for (int ct = 1; ct <= 100000000; ct *= 10) {
performance(ary, ct);
}
System.out.println("--------その他");
othersTest(ary);
System.out.println("--------classTest");
classTest(ary);
}
private static void countTest(int[] ary) {
System.out.println("count1=" + ary.length);
IntStream stream = IntStream.of(ary);
System.out.println("count2=" + stream.count());
}
private static void sumTest(int[] ary) {
int sum1 = 0;
for (int i = 0; i < ary.length; ++i) {
sum1 += ary[i];
}
System.out.println("sum1=" + sum1);
int sum2 = 0;
for (int a : ary) {
sum2 += a;
}
System.out.println("sum2=" + sum2);
System.out.println("sum3=" + Arrays.stream(ary).sum());
System.out.println("sum4=" + IntStream.of(ary).sum());
}
private static void maxTest(int[] ary) {
int max1 = Integer.MIN_VALUE;
for (int i = 0; i < ary.length; ++i) {
max1 = Math.max(max1, ary[i]);
}
System.out.println("max1=" + max1);
int max2 = Integer.MIN_VALUE;
for (int a : ary) {
max2 = Math.max(max2, a);
}
System.out.println("max2=" + max2);
System.out.println("max3=" + Arrays.stream(ary).max());
System.out.println("max4=" + IntStream.of(ary).max());
}
private static void minTest(int[] ary) {
int min1 = Integer.MAX_VALUE;
for (int i = 0; i < ary.length; ++i) {
min1 = Math.min(min1, ary[i]);
}
System.out.println("min1=" + min1);
int min2 = Integer.MAX_VALUE;
for (int a : ary) {
min2 = Math.min(min2, a);
}
System.out.println("min2=" + min2);
System.out.println("min3=" + Arrays.stream(ary).min());
System.out.println("min4=" + IntStream.of(ary).min());
}
private static void sortTest(int[] ary) {
int[] ary1 = ary.clone();
Arrays.sort(ary1);
System.out.println("sort1=" + Arrays.toString(ary1));
IntStream stream2 = IntStream.of(ary).sorted();
System.out.println("sort2=" + Arrays.toString(stream2.toArray()));
System.out.println("orig =" + Arrays.toString(ary));
}
private static void test(int[] ary) {
try {
IntStream stream = IntStream.of(ary);
System.out.println("sumT=" + stream.sum());
System.out.println("maxT=" + stream.max());
System.out.println("minT=" + stream.min());
System.out.println("sortT=" + Arrays.toString(stream.sorted().toArray()));
} catch (RuntimeException e) {
e.printStackTrace();
}
}
private static void performance(int[] ary, int loopCount) {
long S1 = System.currentTimeMillis();
for (int ct = 0; ct < loopCount; ++ct) {
int sum1 = 0;
for (int i = 0; i < ary.length; ++i) {
sum1 += ary[i];
}
}
long G1 = System.currentTimeMillis();
long S2 = System.currentTimeMillis();
for (int ct = 0; ct < loopCount; ++ct) {
int sum2 = 0;
for (int a : ary) {
sum2 += a;
}
}
long G2 = System.currentTimeMillis();
long S3 = System.currentTimeMillis();
for (int ct = 0; ct < loopCount; ++ct) {
int sum3 = Arrays.stream(ary).sum();
}
long G3 = System.currentTimeMillis();
long S4 = System.currentTimeMillis();
for (int ct = 0; ct < loopCount; ++ct) {
int sum4 = IntStream.of(ary).sum();
}
long G4 = System.currentTimeMillis();
System.out.printf("sum(ms) %16dct | %5d | %5d | %5d | %5d |%n",
loopCount, G1 - S1, G2 - S2, G3 - S3, G4 - S4);
}
private static void othersTest(int[] ary) {
System.out.println("orig =" + Arrays.toString(ary));
IntStream stream1 = IntStream.of(ary).distinct();
System.out.println("distinct=" + Arrays.toString(stream1.toArray()));
IntStream stream2 = IntStream.of(ary).skip(1);
System.out.println("skip =" + Arrays.toString(stream2.toArray()));
IntStream stream3 = IntStream.of(ary).limit(5);
System.out.println("limit =" + Arrays.toString(stream3.toArray()));
}
private static void classTest(int[] ary) {
IntStream stream;
stream = IntStream.empty();
System.out.println("empty =" + stream.getClass().getName());
stream = IntStream.range(1, 2);
System.out.println("range =" + stream.getClass().getName());
stream = IntStream.concat(IntStream.empty(), IntStream.empty());
System.out.println("concat =" + stream.getClass().getName());
stream = IntStream.of(ary);
System.out.println("of =" + stream.getClass().getName());
stream = IntStream.of(ary).sorted();
System.out.println("sorted =" + stream.getClass().getName());
stream = IntStream.of(ary).filter(i -> true);
System.out.println("filter =" + stream.getClass().getName());
stream = IntStream.of(ary).map(i -> i);
System.out.println("map =" + stream.getClass().getName());
stream = IntStream.of(ary).distinct();
System.out.println("distinct =" + stream.getClass().getName());
stream = IntStream.of(ary).skip(1);
System.out.println("skip =" + stream.getClass().getName());
stream = IntStream.of(ary).limit(1);
System.out.println("limit =" + stream.getClass().getName());
}
}
各々の出力結果
countTest
--------countTest
count1=12
count2=12
int配列が手元にあるなら要らないだろうというメソッドcount()
。
Streamしか手元にないなら仕方ないだろうが、Streamの要素を数え上げるという処理によって要素が消費されてその後は何もできなくなる(後述)ので、要素数を取得してStreamを捨ててもよいという場合にしか使えない。
sumTest
--------sumTest
sum1=52
sum2=52
sum3=52
sum4=52
これは、配列の要素のsumを計算するのに1行で書けるのでちょっとうれしいかも。
ちなみに、IntStream.of(int...)
は内部でArrays.stream(int[])
を呼んでいる。
maxTest
--------maxTest
max1=9
max2=9
max3=OptionalInt[9]
max4=OptionalInt[9]
これは、OptionalIntが返ってくるのがちょっと微妙なところ。max値がInteger.MIN_VALUEかどうかと比較するのとどっちがいいかという感じ。
minTest
--------minTest
min1=0
min2=0
min3=OptionalInt[0]
min4=OptionalInt[0]
maxと同じく。
sortTest
--------sortTest
sort1=[0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9]
sort2=[0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9]
orig =[5, 2, 8, 2, 9, 1, 3, 0, 5, 6, 4, 7]
元の配列への副作用を発生させないために、ary.clone()
するかIntStream#sorted
を使うかという感じ。ソートされたStreamを取得して更にあれこれやりたい場合には有用。
test
--------1つのstreamで連続処理できるのかテスト
sumT=52
java.lang.IllegalStateException: stream has already been operated upon or closed
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
at java.util.stream.IntPipeline.reduce(IntPipeline.java:461)
at java.util.stream.IntPipeline.max(IntPipeline.java:424)
at Main.test(Main.java:111)
at Main.main(Main.java:19)
これはまぁ予想通り。java.io.InputStreamやjava.io.Readerからの読み込みを(一部を除いて)巻き戻し再実行できないのと同じ。
(補足)sum、max、min、average、countが欲しいだけならsummaryStatistics()
メソッドを使えばいいらしい。
performance
--------パフォーマンスを計ってみる(sumを例に)
sum(ms) 1ct | 0 | 0 | 0 | 0 |
sum(ms) 10ct | 0 | 0 | 0 | 0 |
sum(ms) 100ct | 0 | 0 | 1 | 0 |
sum(ms) 1000ct | 0 | 0 | 9 | 6 |
sum(ms) 10000ct | 2 | 2 | 4 | 16 |
sum(ms) 100000ct | 5 | 28 | 8 | 18 |
sum(ms) 1000000ct | 75 | 66 | 102 | 53 |
sum(ms) 10000000ct | 0 | 0 | 649 | 607 |
sum(ms) 100000000ct | 0 | 0 | 6118 | 6154 |
まぁ、IntStreamオブジェクトを生成するから仕方ない。
othersTest
--------その他
orig =[5, 2, 8, 2, 9, 1, 3, 0, 5, 6, 4, 7]
distinct=[5, 2, 8, 9, 1, 3, 0, 6, 4, 7]
skip =[2, 8, 2, 9, 1, 3, 0, 5, 6, 4, 7]
limit =[5, 2, 8, 2, 9]
distinctは重複要素を除去した新たなStreamを生成する。
skipは先頭の指定された要素数をスキップした新たなStreamを生成する。
limitは先頭の指定された要素数だけを返す新たなStreamを生成する。
その他にfilterとかmapとか色々あるが割愛(謎)。lambda式から逃げてるだけとも言わなくもない(ぉ‥
classTest
--------classTest
empty =java.util.stream.IntPipeline$Head
range =java.util.stream.IntPipeline$Head
concat =java.util.stream.IntPipeline$Head
of =java.util.stream.IntPipeline$Head
sorted =java.util.stream.SortedOps$OfInt
filter =java.util.stream.IntPipeline$9
map =java.util.stream.IntPipeline$3
distinct =java.util.stream.ReferencePipeline$4
skip =java.util.stream.SliceOps$2
limit =java.util.stream.SliceOps$2
java.util.stream.IntStream
がインタフェースだということで、実装クラスがどうなっているのか気になったので列挙してみた。