データ構造の処理のパターンとして「プロになるJava」の「10章データ構造の処理」「値の集合の処理のパターン」では新しいListを作るものと個数を数えるもののふたつを紹介していますが、追加でもうふたつ。
データ構造の処理の例
条件に合う要素全てが別の条件にあうか判定
5文字以上の文字列がすべてyを含むか判定するコードは次のようになります。
package projava; import java.util.List; public class StreamSample3 { public static void main(String[] args) { var data = List.of("yamamoto", "kis", "sugiyama"); var result = true; for (var s : data) { if (s.length() >= 5) { result &= s.contains("y"); } } System.out.println(result); } }
ここで&=
は変数の値と&演算、つまりandを行ったものを、元の変数に割り当てなおすという複合代入演算子でresult = result & s.contains("y")
と同じ動きになります。
条件に合う要素のひとつでも別の条件にあうか判定
5文字以上の文字列がひとつでもgを含むか判定するコードは次のようになります。
package projava; import java.util.List; public class StreamSample4 { public static void main(String[] args) { var data = List.of("yamamoto", "kis", "sugiyama"); var result = false; for (var s : data) { if (s.length() >= 5) { result |= s.contains("g"); } } System.out.println(result); } }
ここで|=
は変数の値と|演算、つまりorを行ったものを、元の変数に割り当てなおすという複合代入演算子でresult = result | s.contains("g")
と同じ動きになります。
共通の構造
新しいListを作る、個数を数える、すべてがyを含むか判定、どれかがgを含むか判定のサンプルを見ましたが、これらには共通の構造があります。
var result = 初期値; for (var s : data) { if (s.length() >= 5) { resultに新たな結果を加える処理 } }
この中で、初期値や新たな結果を加える処理は次のようになっています。
処理 | 初期値 | 結果を加える処理 |
---|---|---|
新しいList | new ArrayList |
result.add(s) |
個数を数える | 0 | result++ |
全部yを含むか | true | result &= s.contains("y") |
gを含むものがあるか | false | result |= s.contains("g") |
Stream
プログラムにおいて「パターンがあるのであれば共通化して覚えなくてもよくしよう」というのが大切ですが、データ構造の処理を共通化するのがStreamといえます。
今回の処理はそれぞれ、allMatchとanyMatchを終端処理に使うことで書き換えることができます。
var result = data.stream() .filter(s -> (s.length() >= 5)) .allMatch(s -> s.contains("y"));
var result = data.stream() .filter(s -> (s.length() >= 5)) .anyMatch(s -> s.contains("g"));
これらをまとめると、次のようになります。
処理 | 終端処理 |
---|---|
新しいList | toList() |
個数を数える | count() |
全部yを含むか | allMatch(s -> s.contains("y")) |
gを含むものがあるか | anyMatch(s -> s.contains("g")) |