[リサーチ・メモ] Streamについて

## 背景
最近streamを良く利用するが改めての理解としてよく使用するものと、ドキュメントを見て今後使えそうなものをメモとして纏める。

## 中間操作
### filter：条件に一致する要素のみを含むStreamを返す
```
List<String> words = Arrays.asList("apple", "banana", "cherry", "date");

List<String> result = words.stream()
    .filter(word -> word.startsWith("a"))
    .collect(Collectors.toList());
// 出力: [apple]
```

### map：要素を別の要素に変換する
```
List<String> words = Arrays.asList("apple", "banana", "cherry");

List<Integer> wordLengths = words.stream()
    .map(String::length)
    .collect(Collectors.toList());
// 出力: [5, 6, 6]
```
### sorted：要素をソートする
```
list.stream().sorted().forEach(System.out::println);
```
※sorted後にfilterをしても順序は変わらずにfilterされる
　降順の場合は.sorted(Comparator.reverseOrder())を使用する
### flatMap：各要素を複数の要素に変換する(複数のStreamを1つにして使用できる)
```
List<String> sentences = Arrays.asList("Hello World", "Java Stream");

Stream<String> wordsStream = sentences.stream()
    .flatMap(sentence -> Arrays.stream(sentence.split(" ")));

wordsStream.forEach(System.out::println);
// 出力:
// Hello
// World
// Java
// Stream

```

### distinct：重複要素を削除する
```
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);

List<Integer> distinctNumbers = numbers.stream()
    .distinct()
    .collect(Collectors.toList());
// 出力: [1, 2, 3, 4, 5]
```
※要素の等価性はequalsメソッドで判定される
### limit：Streamから指定した数の要素だけ取得
```
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

List<Integer> firstThree = numbers.stream()
    .limit(3)
    .collect(Collectors.toList());
// 出力: [1, 2, 3]
```

### skip：Streamから指定した数の要素をスキップする
```
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

List<Integer> afterSkippingTwo = numbers.stream()
    .skip(2)
    .collect(Collectors.toList());
// 出力: [3, 4, 5]
```
## 終端操作
### forEach
```
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");
names.forEach(System.out::println);
```
### collect：Streamの要素をリスト、セット、マップなどのコレクションに変換する
```
Stream<String> fruits = Stream.of("apple", "banana", "cherry");
List<String> fruitList = fruits.collect(Collectors.toList());
```
### reduce：Streamの要素を単一の結果に結合する
※初期値を持つ場合
```
Stream<Integer> numbers = Stream.of(1, 2, 3, 4);
Integer sum = numbers.reduce(0, Integer::sum);
```
※初期値を持たない場合
```
Stream<Integer> numbers = Stream.of(1, 2, 3, 4);
Optional<Integer> sum = numbers.reduce(Integer::sum);
```
### count：Streamに含まれる要素の数を返す
```
Stream<String> animals = Stream.of("cat", "dog", "elephant");
long count = animals.count();
// 出力: 3
```
### toArray：Streamの要素を配列に変換する
```
Stream<String> colors = Stream.of("red", "green", "blue");
String[] colorArray = colors.toArray(String[]::new);
```
## 短絡操作
### findFirst：Streamの最初の要素を返す
```
Stream<Integer> numbers = Stream.of(1, 2, 3, 4);
Optional<Integer> first = numbers.findFirst();
// 出力: Optional[1]
```

※Optionalで返すものは、isPresent()で値の有無を確認し、get()で取得する
　空に対してget()を実施すると「NoSuchElementException」がスローされる
### anyMatch：Streamの要素のうち、指定された条件を満たすものが1つでもある場合にtrueを返す
```
Stream<String> words = Stream.of("apple", "banana", "cherry");
boolean result = words.anyMatch(word -> word.startsWith("b"));
// 出力: true（"banana"が条件を満たしているため）
```
### allMatch：Streamのすべての要素が指定された条件を満たす場合にtrueを返す
```
Stream<Integer> numbers = Stream.of(2, 4, 6, 8);
boolean result = numbers.allMatch(num -> num % 2 == 0);
// 出力: true（全ての数字が偶数であるため）
```

### noneMatch：Streamのすべての要素が指定された条件を満たさない場合にtrueを返す
```
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");
boolean result = names.noneMatch(name -> name.startsWith("Z"));
// 出力: true（どの名前もZで始まらないため）
```
### findAny：Streamの要素のうち、どれか1つを返す
```
Stream<String> colors = Stream.of("red", "green", "blue");
Optional<String> anyColor = colors.findAny();
// 出力: 例) Optional[red]
```