Help us understand the problem. What is going on with this article?

5分で分るJava Stream API

この記事ではJava Stream APIが読めない人を対象にしています。

以下の人にオススメです
- Javaとか昔は書いてたけど最近は書いてない
- Stream APIが読めなくてコーディングを辞めた
- とにかく時間がないから勘所だけ知りたい

最初に

Java Stream APIとは、 InputStreamや、OutputStreamなどのI/Oクラスとは関係ありません。
List,SetなどのCollection Object,または配列などのループ可能な要素をループの中で一度だけ処理する仕組みの事を言います。
※Streamは一度処理すると再利用できません。ただし、Streamはchain(連鎖)させることで複数の処理が可能です。

Stream APIを利用して行うものは、よく使うのは以下の2点です

  • エンティティを変換する(mapメソッド)
  • コレクションをフィルターする(filterメソッド)

Javaのコードを記載します。

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class StreamTest {
    public static void main(String[] args) {
        List<String> csvList = new ArrayList<>();
        csvList.add("田中 直樹,MAN");
        csvList.add("北村 一輝,MAN");
        csvList.add("加藤 しずか,WOMAN");
        csvList.add("小野 妹子,UNKNOWN");
        // 1.エンティティを変換する。(map)
        List<Person> persons = csvList.stream().map(Person::convertPersonFromCSV).collect(Collectors.toList());

        // 2.エンティティをフィルターする。(filter)
        List<Person> mens = persons.stream().filter(p -> p.getGender() == Gender.MAN).collect(Collectors.toList());

        System.out.println("Print all persons");
        persons.forEach(System.out::println);

        System.out.println("Print mens only");
        mens.forEach(p -> System.out.println(p.getName()));
    }

    enum Gender {
        MAN,
        WOMAN,
        UNKNOWN;
    }

    static class Person {
        private String name;
        private Gender gender;

        public Person(String name, Gender gender) {
            this.name = name;
            this.gender = gender;
        }

        @Override
        public String toString() {
            return String.format("My name is %s . \r\nMy gender is %s.", name, gender);
        }

        public String getName() {
            return this.name;
        }

        public Gender getGender() {
            return this.gender;
        }

        public static Person convertPersonFromCSV(String csv) {
            String[] csvStrings = csv.split(",");
            if (csvStrings.length != 2) throw new IllegalArgumentException("csv is illegal format.");
            return new Person(csvStrings[0], Gender.valueOf(csvStrings[1]));
        }
    }
}

それでは、順番に上記を見ていきましょう

エンティティを変換する

エンティティを変換する際は、mapメソッドを使用します。
mapメソッドで変換、collectメソッドでStreamを再度Collection型に変換します。

主に以下の3種類の書き方が出来ます。

csvList.stream().map(Person::convertPersonFromCSV).collect(Collectors.toList());
csvList.stream().map(csv -> Person.convertPersonFromCSV(csv)).collect(Collectors.toList());
csvList.stream().map(csv -> {
                         Person person = Person.convertPersonFromCSV(csv);
                         return person;
                     }).collect(Collectors.toList());

どれもやっていることは同じで、csvListの要素であるStringを取得して、
Personオブジェクトに変換して返却するメソッドを実行しています。
- 1番目は引数のcsvを省略する書き方
- 2番目はreturnメソッドを省略して1行で記述する書き方
- 3番目は何も省略しない書き方

Streamを使うことで、Listを1行(ワンライナー)でListに変換することが出来ました。
Streamを使用することのメリットの一つとして、コードの記述量を減らすことが出来るというものがあります。

以下は時間のない人は飛ばしてください。

  • csvList.stream()
    • Streamオブジェクトを取得します。
  • map(Person::convertPersonFromCSV)
    • mapメソッドの引数として、csvListのGenericインターフェースであるStringが与えられます。
    • Personクラスのエンティティ変換メソッドを呼び出しentityの変換を行い、entityクラスを返却します。
    • Functionインターフェースを実装したメソッドを使用して、StringクラスをPersonクラスに変換して返却しています。
  • collect(Collectors.toList())
    • 変換されたPersonを集めます。
    • Collectors.toList()でListクラスに追加していきます。
    • Collectors.toXXX()でSetやMapにも変換できます。toMapの場合、keyとvalueを返却する2つのFunctionを記述する必要があります。
  • メソッドの処理の順序としては、「mapで変換,collectでStreamで処理したオブジェクトをリストに格納」という処理を繰り返すイメージとなります。

コレクションをフィルターする

コレクションから特定の要素を除外して、新しいコレクションオブジェクトを作成することが出来ます。
filterメソッドを使用して、残したい対象のオブジェクトを記載します。

persons.stream().filter(p -> p.getGender() == Gender.MAN).collect(Collectors.toList());

Streamを使うことで、Listから男性のみを抽出した新しいコレクションをワンライナーで作成できました。
- filter(p -> p.getGender() == Gender.MAN)
- Personを引数に取り、booleanを返却します。

Stream APIを使用してよくやる他のこと

  • findAny
    • filterと組み合わせて、特定の要素が存在するかどうかを検出する。
  • sum
    • mapToIntと組み合わせて、コレクションの合計数を算出する。
  • reduce
    • コレクションの要素を結合して一つのオブジェクトに纏める。
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away