filter で絞り込む
数えるだけなのに、部品が 4 つ要る
ログの行から ERROR を含む行が何本あるかを数える、というだけの処理を for で書くと次のようになります。
Java
int count = 0;
for (String line : logs) {
if (line.contains("ERROR")) {
count++;
}
}カウンタの初期化、ループ、判定の if、そして count++。やりたいことは「ERROR の行を数える」の一言なのに、部品が 4 か所に散らばります。しかも count は途中で書き換わる変数なので、後ろに処理を足すたびに「今いくつ入っているのか」を追いかける羽目になります。
同じ処理を Stream で書くと、こうなります。
Java
long count = logs.stream()
.filter(line -> line.contains("ERROR"))
.count();filter が if の役目を、count がカウンタの役目を引き受けています。書く量が減ったこと以上に、上から読むと「ログを流して、ERROR のものだけ残して、数える」とそのまま日本語になるのが利点です。
filter は「通すか、通さないか」だけを決める
filter に渡した line -> line.contains("ERROR") は、要素を 1 つ受け取って true か false を返す式です。Stream を流れてきた要素を 1 つずつこの式にかけて、true になったものだけを次へ通します。false になったものは、そこで捨てられます。
大事なのは、filter が返すのもまた Stream だという点です。つまり filter を書いた時点では、まだ何も起きていません。
Java
logs.stream().filter(line -> line.contains("ERROR"));これを実行しても、1 行も判定されませんし、画面にも何も出ません。count() のように「ふつうの値」を返すメソッドを最後に呼んだ瞬間に、はじめて全体が動き出します。filter のように Stream を返すものを中間操作、count() のように値を返して打ち止めになるものを終端操作と呼びます。
終端操作を書き忘れて「動かない」と悩むのは、Stream を覚えたての人がほぼ全員 1 度は通る道です。処理が走っていないときは、まず行末を見てください。
元のリストは 1 件も減らない
filter は条件に合わない要素を消しているように見えますが、logs そのものは何も変わりません。通す要素を選んで流しているだけで、元のリストは読んでいるだけです。
Java
List<String> logs = List.of("INFO ok", "ERROR ng", "INFO ok");
long ng = logs.stream().filter(line -> line.contains("ERROR")).count();
System.out.println(logs.size()); // 3 のまま元のリストを守ったまま別の答えを何通りも取り出せるので、同じデータに対して条件を変えながら何度でも stream() を呼べます。
やってみよう
Solution.evenCount(int[] arr) を完成させて、配列の中の偶数の個数を返してください。
int[] から Stream を作るときは Arrays.stream(arr) または IntStream.of(arr) を使います。あとは通したい要素の条件を filter に渡して、最後に個数を数える終端操作を呼ぶだけです。
型に 1 つだけ注意点があります。個数を数える count() が返すのは long で、このメソッドの戻り値は int です。そのままでは返せないので (int) でキャストしてください。
空配列や、奇数しか入っていない配列を渡したときは 0 が返ります。if で先に長さを調べる必要はありません。要素が 1 つも通らなければ、数えた結果は自然に 0 になります。
要件
Arrays.stream(arr)またはIntStream.of(arr)を使ってIntStreamを作ることfilterにラムダ式を渡して偶数 (n % 2 == 0) だけ残すこと- 終端操作
count()の戻り値 (long) をintにキャストして返すこと
入出力例
evenCount([1,2,3,4,5,6]) → 3
evenCount([]) → 0
evenCount([1,3,5]) → 0
evenCount([2,4,6,8]) → 4
evenCount([0,-2,-3,7,-4]) → 3