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