0
1

Stream API について理解を深める

Last updated at Posted at 2024-09-17

Stream APIとは

JavaのStream APIは、コレクション(リスト、セット、マップなど)のデータ操作を簡潔かつ効率的に行うための機能です。Java 8で導入され、データ処理をより宣言的(何をするかに焦点を当てる)に記述できるようにします。これにより、コレクション操作のためのコードが短くなり、読みやすくなります。

napkin-selection (1).png

Stream APIの基本概念

Stream: データのシーケンスを表し、要素に対してさまざまな操作(フィルタリング、変換、集約など)を行うためのインターフェース。
中間操作: ストリームの要素を変換する操作。結果として新しいストリームを返します(例: map, filter, sorted)。
終端操作: ストリームの処理を終了し、結果を返す操作。ストリームを消費して最終結果を返します(例: collect, forEach, reduce)。

Stream APIの主な特徴

データの操作を宣言的に記述: Stream APIを使用することで、forループを使うことなくデータ操作を記述できます。
遅延評価: ストリームの中間操作は遅延評価されます。つまり、終端操作が呼び出されるまで中間操作は実行されません。
無変更性: ストリームは元のデータソースを変更せず、新しいストリームを生成します。

1. filter

条件に合う要素を選択します。


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
   .filter(n -> n % 2 == 0) // 偶数のみを選択
   .collect(Collectors.toList());

//例: リストから偶数だけを選択する。

2. map

各要素を別の形式に変換します。


List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> nameLengths = names.stream()
   .map(String::length) // 各名前の長さに変換
   .collect(Collectors.toList());

//例: 名前のリストをそれぞれの名前の長さに変換する。

3. collect

Streamの結果をリストやセット、マップなどに収集します。


List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> nameList = names.stream()
   .collect(Collectors.toList());

//例: Streamの結果をリストに収集する。

4. forEach

各要素に対してアクションを実行します。


List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
   .forEach(System.out::println); // 各名前を表示

//例: リストの各要素をコンソールに出力する。

5. reduce

要素を結合して単一の結果を生成します。


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
   .reduce(0, (a, b) -> a + b); // 合計を計算

//例: リストのすべての要素の合計を計算する。

6. sorted

要素をソートします。


List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2);
List<Integer> sortedNumbers = numbers.stream()
   .sorted() // 昇順にソート
   .collect(Collectors.toList());

//例: リストの要素を昇順にソートする。

7. distinct

重複する要素を削除します。


List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> distinctNumbers = numbers.stream()
   .distinct() // 重複を削除
   .collect(Collectors.toList());

//例: リストから重複する要素を削除する。

8. limit

最初のN個の要素を取得します。


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> limitedNumbers = numbers.stream()
   .limit(3) // 最初の3つの要素を取得
   .collect(Collectors.toList());

//例: リストの最初の3つの要素を取得する。

9. skip

最初のN個の要素をスキップします。


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> skippedNumbers = numbers.stream()
   .skip(2) // 最初の2つの要素をスキップ
   .collect(Collectors.toList());

//例: リストの最初の2つの要素をスキップする。

10. findFirst

最初の要素を返します。


List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Optional<String> first = names.stream()
   .findFirst(); // 最初の要素を取得

//例: リストの最初の要素を取得する。

例: 会社と従業員のデータを処理するstreamAPI

この例では、会社 (Company) と従業員 (Employee) のデータを持っています。各会社は複数の従業員を持ち、各従業員には部門が割り当てられています。このデータを処理して、部門ごとの従業員のリストを取得する処理を実装します。

class Employee {
    private String name;
    private String department;

    public Employee(String name, String department) {
        this.name = name;
        this.department = department;
    }

    public String getName() {
        return name;
    }

    public String getDepartment() {
        return department;
    }

    @Override
    public String toString() {
        return name + " (" + department + ")";
    }
}

class Company {
    private String name;
    private List<Employee> employees;

    public Company(String name, List<Employee> employees) {
        this.name = name;
        this.employees = employees;
    }

    public List<Employee> getEmployees() {
        return employees;
    }

    public String getName() {
        return name;
    }
}

public class AdvancedStreamExample {
    public static void main(String[] args) {
        List<Company> companies = Arrays.asList(
            new Company("CompanyA", Arrays.asList(
                new Employee("Alice", "HR"),
                new Employee("Bob", "Engineering"),
                new Employee("Charlie", "Engineering")
            )),
            new Company("CompanyB", Arrays.asList(
                new Employee("David", "Marketing"),
                new Employee("Eve", "HR"),
                new Employee("Frank", "Engineering")
            ))
        );

        // Stream APIを使用して、部門ごとに従業員をグループ化
        Map<String, List<Employee>> employeesByDepartment = companies.stream()
            .flatMap(company -> company.getEmployees().stream()) // 各会社の従業員を一つのStreamに平坦化
            .collect(Collectors.groupingBy(Employee::getDepartment)); // 部門ごとにグループ化

        // 結果の出力
        employeesByDepartment.forEach((department, employees) -> {
            System.out.println(department + ": " + employees);
        });
    }
}

出力結果
このコードの出力は以下のようになります:

HR: [Alice (HR), Eve (HR)]
Engineering: [Bob (Engineering), Charlie (Engineering), Frank (Engineering)]
Marketing: [David (Marketing)]

【参考】

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1