Stream を作る
絞り込みや並べ替えのメソッドは、List には生えていない
Java 8 で入った Stream API を使うと、コレクションの中身を「流れ」として扱い、絞り込みや並べ替えや集計をメソッドをつないで書けます。ただし、その便利なメソッドたちは List や Set そのものには生えていません。names.sorted() とは書けないのです。
使うには、まずコレクションを Stream に変える必要があります。それが stream() です。
Java
List<String> names = List.of("Alice", "Bob", "Carol");
Stream<String> stream = names.stream();stream() を呼んでも、元の names は何も変わりません。中身をコピーしているわけでもありません。「ここから 1 件ずつ流し出せます」という口を用意しただけです。Set も Map の values() も同じように stream() を持っているので、コレクションからの入り口はこれ 1 つで足ります。
流れを作っただけでは、何も出てこない
Stream は、作った時点では動きません。最後に終端操作と呼ばれるメソッドを呼んで、はじめて要素が流れ始めます。
Java
long count = names.stream().count();
System.out.println(count);count() は要素数を返す終端操作です。戻り値が long になっているのは、Stream が数十億件規模のデータも扱う前提で設計されているからです。int の上限はおよそ 21 億なので、そこでは足りない場面があります。
終端操作を書き忘れると、本当に何も起きません。エラーも出ません。これは遅延評価という仕組みで、途中の操作をつないだだけでは処理が始まらないようになっています。
配列には stream() が無い
int[] や String[] のような配列には stream() メソッドがありません。配列から流れを作るときは Arrays.stream を使います。
Java
import java.util.Arrays;
int[] scores = {80, 95, 72};
IntStream stream = Arrays.stream(scores);int[] を渡すと、返るのは Stream<Integer> ではなく IntStream です。sum() や average() のような数値専用のメソッドが使えるうえ、1 件ごとに Integer へ包み直す無駄も出ません。double[] なら DoubleStream、long[] なら LongStream が対応します。
ここで Stream.of(scores) と書かないよう気をつけてください。Stream.of は Stream.of("a", "b", "c") のように値を並べるためのもので、配列を 1 つ渡すと「要素が 1 つだけ、その中身が配列」という妙な流れになってしまいます。
流し終わった水は戻ってこない
一度終端操作を呼んだ Stream は、二度と使えません。
Java
Stream<String> stream = names.stream();
long a = stream.count();
long b = stream.count(); // IllegalStateException2 回目で stream has already been operated upon or closed という実行時エラーになります。Stream は水そのものではなく水の流れなので、流れ終わったあとには何も残っていない、と考えると腑に落ちます。
元のコレクションは手元に残っているので、必要なら names.stream() をもう一度呼べば済みます。Stream を変数に取っておかず、その場でつないで書き切るのが安全です。
要件
- ファイル先頭で
import java.util.Arrays;を書くこと Arrays.stream(arr)でIntStreamを生成し、count()で要素数を取得することcount()の戻り値はlongなので、(int)でキャストしてintとしてreturnすること
入出力例
streamCount([1,2,3]) → 3
streamCount([]) → 0
streamCount([42]) → 1
streamCount([10,20,30,40,50]) → 5