「Stream API」は、Java 8で導入された機能で、配列やコレクションなどの集合体を扱う為のもので、特定の条件でデータを抽出したり、中身を別の型のコレクションに移し替えたり、合計値を求める時など、コレクションに対する操作を for 構文などの繰り返しを使わない形で値の集合を操作出来る便利なAPIです。
「中間操作」と「終端操作」
Stream API 操作は、生成、中間操作、終端操作の三段階に分けられます。
まずコレクションなどのデータソースから Stream の「生成」を行い、「中間操作」で条件による絞り込みや並び替えなどを経て、「終端操作」で最終的な処理結果を出力するのが基本的な流れです。
中間操作は複数指定することができますが、終端操作は一度の命令で1回しか実行できない特徴があるので覚えておきましょう。
本記事で使用するサンプルデータ
List<User> userList = Arrays.asList(
new User(1, "teamA", 30 ),
new User(2, "teamB", 50 ),
new User(3, "teamA", 10 ),
new User(4, "teamB", 40 )
);
forEach
forEach は、要素を1つずつ取り出し何らかの処理をするメソッドです。
userList.stream()
.forEach(System.out::print);
// user1 user2 user3 user4
filter
filter は、引数で指定した条件に一致する要素を抽出するメソッドです。
userList.stream()
// teamBのみに抽出
.filter(e -> "teamB".equals(e.team))
.forEach(System.out::print);
// user2 user4
map
map は、Stream の要素を別の型に変換するメソッドです。
userList.stream()
// IDだけのリストに加工
.map(e -> e.id)
.forEach(System.out::print);
// 1 2 3 4
flatMap
flatMapは、mapと同じく Stream の要素を別の型に変換するメソッドです。map が1対1で要素の型を変換するのに対し、flatMap は1対多で変換をします。
つまり、入力した要素を複数の値に増殖するときなどに flatMap を使用します。
userList.stream()
// IDとチームのリストに加工
.flatMap(e -> Stream.of(e.id, e.team))
.forEach(System.out::print);
// 1 teamA 2 teamB 3 teamA 4 teamB
distinct
distinctは、Stream の要素の中で、値もしくわ指定したキーが重複している要素を取り除くメソッドです。
userList.stream()
.map(e -> e.team)
// チームの重複を取り除く
.distinct()
.forEach(System.out::print);
// teamA teamB
sorted
sortedは、Stream の要素を並び替えるメソッドです。
userList.stream()
// スコアの降順→IDの昇順でソート
.sorted(Comparator.comparing(User::getScore).reversed().thenComparing(User::getId)) .forEach(System.out::print);
// user2 user4 user1 user3
limit
limitは、Stream の先頭から指定した位置までを取り出すメソッドです。
userList.stream()
// 先頭から3つだけに絞る
.limit(3)
.forEach(System.out::print);
// user1 user2 user3
skip
skipは、Stream の指定した位置から最後までを取り出すメソッドです。
userList.stream()
// 2番目以降に絞る
.skip(1)
.forEach(System.out::print);
// user2 user3 user4
collect
collect は、可変リダクション操作と呼ばれ、中間操作で抽出した一連の要素に特定の処理を適用して1つにまとめる操作をします。
主に、 Collections クラスを使って、List や HashSet などのコレクションクラス変換したりします。要素の値を1つの String の値に結合したりします。
Collectors.toList
Collectors.toList は、Streamを List クラスに変換します。
List<Integer> userIdList = userList.stream()
.map(e -> e.id)
.collect(Collectors.toList());
// 1 2 3 4
Collectors.toMap
Collectors.toMapは、Streamを Map クラスに変換します。
Map<Integer, User> userMap = userList.stream()
.collect(Collectors.toMap(User::getId, e -> e));
// {1=user1 , 2=user2 , 3=user3 , 4=user4 }
Collectors.groupingBy
Collectors.groupingByは、Streamを グループごとに分別します。
Map<String, List<User>> groupMap = userList.stream().collect(
Collectors.groupingBy(User::getTeam));
// {teamA=[user1 , user3 ], teamB=[user2 , user4 ]}
count
count は、Stream の件数を取得するメソッドです。
long conut = userList.stream().count();
// 4
max / min
max / min は、Stream の最大値 / 最小値 を取得するメソッドです。
Optional value = userList.stream()
.map(e -> e.getScore())
// 最大のスコアを取得
.max(Comparator.naturalOrder());
// Optional[50]
Optional value = userList.stream()
.map(e -> e.getScore())
// 最小のスコアを取得
.min(Comparator.naturalOrder());
// Optional[10]
sum
sum は、Stream の合計値を取得するメソッドです。
long sum = userList.stream()
.mapToLong(e -> e.getScore())
// 合計のスコアを取得
.sum();
// 130
average
average は、Stream の平均値を取得するメソッドです。
OptionalDouble average = userList.stream()
.mapToLong(e -> e.getScore())
// スコアの平均を取得
.average();
// OptionalDouble[32.5]