Java Streamからの配列、リストの作り方。

この記事では、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がありません。


リストからグルーピングで多重Mapを作ろう。 (Java)

コメントを残す