- Contents -
この記事では、Streamの基本的な使い方。
特に、Streamから、配列、またはリストを生成する方法について解説します。
Streamとは
Java8から追加された、Stream。
Streamという名称からも分かるように、データの流れを扱う機能になります。
流れの中で処理を行う、処理メソッド。
流れの最後で集約する為の、集約メソッドを使って、データの流れを操作します。
処理メソッド
処理メソッドは、Streamで流れてきたデータを、
間引く、変換する、分離する、並べ替えるなどの処理を加えるものです。
- filter
- map (mapToInt, mapToLong)
- flatMap
- sort (reverse)
集約メソッド
Streamは最後に集約され、なんらかの成果物となります。
- collect (toList, toSet, toMap, groupingBy)
- reduce
- max, min, sum
実装サンプル
実装サンプルをお見せする前に、今回のStreamに流がすデータは
下記のようなPersonクラスとします。
long, int, String のメンバ変数を持つクラスですね。
今回はこのクラスのリストから、Streamでデータを加工してみましょう。
class Person {
private long _id;
private String _name;
private int _age;
public Person(long id, String name, int age) {
_id = id;
_name = name;
_age = age;
}
public long id() {
return _id;
}
public String name() {
return _name;
}
public int age() {
return _age;
}
}
扱う、データのサンプルは適当です。
List<Person> list = List.of(
new Person(12345678900L, "hoge", 18),
new Person(12345678901L, "piyo", 19),
new Person(12345678902L, "foo", 20),
new Person(12345678903L, "bar", 21));
Streamから配列の作りかた
toArrayを使う為には、
IntStream, LongStreamにしておかないといけない事に注意。
IntStrem, LongStreamは、Integer, Longではなく、
int, long というプリミティブ型用に特化したストリームです。
to int[]
int[] intArr = list.stream() // Stream<Person>
.mapToInt(Person::age) // IntStream
.toArray();
to long[]
long[] longArray = list.stream() // Stream<Person>
.mapToLong(Person::id) // LongStream
.toArray();
to String[]
String[] strArray = list.stream() // Stream<Person>
.map(Person::name) // Stream<String>
.toArray(String[]::new); // .toArray(c -> new String[c])と同じ
Streamからリストの作りかた
List<>
クラスに変換するには、
要素はプリミティブ型ではなく、すべてObject型を継承したクラスになります。
Steam<>
であれば、Collectors.toList()
でなんでもリスト化できます。
to List<Integer>
List<Integer> intList = list.stream() // Stream<Person>
.map(Person::age) // Stream<Integer>
.collect(Collectors.toList());
to List<Long>
List<Long> longList = list.stream() // Stream<Person>
.map(Person::id) // Stream<Long>
.collect(Collectors.toList());
to List<String>
List<String> strList = list.stream() // Stream<Person>
.map(Person::name) // Stream<String>
.collect(Collectors.toList());
まとめ
Streamは、
for文を使わなくても、コードが簡素に書けるようになります。
見た目もわかりやすくなります。
また、Streamと、for文、どちらを使ってもほぼ同じ処理を書くことができます。
しかし、全部をStreamで書くのも、なんだかやり過ぎな感じになってしまいます。
どちらを使ったらいいのか、場合によるかもしれませんが、
自分の場合は、以下の基準で使い分けるようにしています。
- データを加工する場合は、Streamを使う
- データ毎に処理していく場合は、for文を使う。
Streamは、流れてきたデータを加工するもの
という範囲で使うのが、直感的で読みやすいコードになると思います。
forEachメソッドを使えば、for文を使わなくても全てStreamで書けますが、
たいてい処理が目的の場合は、
キャプチャした変数などに影響を与えるようなコードになってしまうので、
ちょっと周りくどい感じがあります。
しかも、forEachは、for文のような breakがありません。