MENU

【保存版】Stream APIの使い方を徹底解説!現場で使える実践テクニック集

こんにちは!バックエンドエンジニアのキョンです。今回は、Java 8から追加されたStream APIについて、実務での経験を元に詳しく解説していきます。

目次

1. Stream APIとは?

導入背景

正直に言うと、私も最初はStream APIの必要性がピンときませんでした。forループで十分じゃない?って思ってたんです。

でも、実際の開発現場で大量のデータを扱う中で、その真価に気づきました。特に:

  • コードの可読性向上
  • 並列処理の簡単な実装
  • 関数型プログラミングの恩恵

これらが実感できたんです。

2. 基本的な使い方

コレクションからStreamの生成

List<String> names = Arrays.asList("田中", "鈴木", "佐藤");

// Stream生成
Stream<String> stream = names.stream();

よく使う中間操作

List<User> users = getUserList();  // ユーザーリストを取得

users.stream()
    .filter(user -> user.getAge() >= 20)  // 20歳以上をフィルタリング
    .map(User::getName)                    // 名前を取得
    .sorted()                              // ソート
    .distinct()                            // 重複除去
    .forEach(System.out::println);         // 出力

3. 実践的なユースケース

ケース1: データの集計

実際の案件で使用した売上集計の例です:

public class SalesAggregator {
    public Map<String, Double> aggregateSalesByProduct(List<Sale> sales) {
        return sales.stream()
            .collect(Collectors.groupingBy(
                Sale::getProductName,
                Collectors.summingDouble(Sale::getAmount)
            ));
    }
    
    public DoubleSummaryStatistics getSalesStatistics(List<Sale> sales) {
        return sales.stream()
            .mapToDouble(Sale::getAmount)
            .summaryStatistics();
    }
}

ケース2: データ変換処理

API連携でよく使うデータ変換処理です:

public class DataTransformer {
    public List<UserDTO> transformUsers(List<User> users) {
        return users.stream()
            .filter(user -> user.getStatus().equals("ACTIVE"))
            .map(user -> new UserDTO(
                user.getId(),
                user.getFullName(),
                user.getEmail(),
                user.getAge()
            ))
            .collect(Collectors.toList());
    }
}

ケース3: 並列処理

大量データ処理での実践例です:

public class BatchProcessor {
    public void processLargeData(List<Data> dataList) {
        dataList.parallelStream()
            .filter(this::isValid)
            .map(this::processData)
            .forEach(this::saveToDatabase);
    }
    
    private boolean isValid(Data data) {
        // バリデーションロジック
        return data != null && data.getValue() != null;
    }
    
    private ProcessedData processData(Data data) {
        // 重い処理
        return new ProcessedData(data);
    }
}

4. パフォーマンスとベストプラクティス

パフォーマンス最適化のコツ

実務で学んだ最適化のポイントです:

// 悪い例:不必要なStream生成
list.stream().forEach(item -> {
    // 処理
});

// 良い例:直接forEachを使用
list.forEach(item -> {
    // 処理
});

// 悪い例:複数回のStream生成
long count = list.stream().filter(x -> x > 0).count();
double avg = list.stream().filter(x -> x > 0).mapToInt(x -> x).average().orElse(0);

// 良い例:Stream再利用
Stream<Integer> filteredStream = list.stream().filter(x -> x > 0);
long count = filteredStream.count();
double avg = filteredStream.mapToInt(x -> x).average().orElse(0);

メモリ使用量の最適化

public class LargeDataProcessor {
    public void processLargeFile(String filePath) {
        try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
            lines.filter(line -> !line.isEmpty())
                 .map(this::processLine)
                 .forEach(this::saveResult);
        } catch (IOException e) {
            logger.error("ファイル処理エラー", e);
        }
    }
}

5. よくあるミスと解決策

Stream再利用の罠

// 悪い例:Streamの再利用
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println);  // IllegalStateException!

// 良い例:必要に応じて新しいStreamを生成
list.stream().forEach(System.out::println);
list.stream().forEach(System.out::println);

並列処理での注意点

// 悪い例:副作用のある処理を並列実行
List<String> result = Collections.synchronizedList(new ArrayList<>());
stream.parallel().forEach(result::add);  // 順序が保証されない!

// 良い例:collectを使用
List<String> result = stream.parallel()
    .collect(Collectors.toList());

まとめ

Stream APIは、使いこなせると本当に便利なツールです。私の経験上、以下のポイントを押さえておくと良いでしょう:

  1. 基本的な操作(filter, map, collect)を完璧に使えるようにする
  2. パフォーマンスを意識した使い方を心がける
  3. 並列処理の特性を理解する
  4. 適材適所を見極める(すべてをStreamで書く必要はない)

今後の学習のために

  • Java Stream APIのドキュメント
  • Java 8 in Action(書籍)
  • モダンJava実践ガイド

次回は「Java Lambda式の実践的な使い方」について解説する予定です。お楽しみに!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次