【JavaGold】ストリームAPI

# ストリームAPI

### java.util.Optionalクラス															
Optionalは、値が存在するかどうかを表現するために使用される。
値が存在しない場合にnullを扱う代わりに、Optionalを使用することで明示的に値の存在または不在を表現することができる。

#### メリット
* nullチェックの簡略化
明示的に値が存在しない場合を考慮できる。
これにより、NullPointerExceptionを回避することができる。

* 読みやすさと安全性の向上
値の存在性チェック、値が存在しない場合のデフォルト値の提供などを実行することができる。
つまり、簡潔かつ安全に値の存在性を確認し、適切な処理を行うことができる。

### Optionalインスタンスを作成する際に使用する。
* empty()メソッド
* orElse()メソッド
* of()メソッド
* ofNullable()メソッド

<table>
  <caption>各メソッドの比較</caption>
  <thead>
    <tr>
      <th>メソッド</th>
      <th>インスタンスの中身</th>
      <th>使う場面</th>
    </tr>
  </thead>
  <tr>
    <td>empty</td>
    <td>空</td>
    <td>値が存在しないことを明示する場合</td>
  </tr>
  <tr>
    <td>of</td>
    <td>null以外の値</td>
    <td>値でnullを許容したくない場合</td>
  </tr>
  <tr>
    <td>ofNullable</td>
    <td>nullを含む値</td>
    <td>値がnullである可能性がある場合</td>
  </tr>
</table>

* of()メソッドはnullの場合、例外をスローする。
* 上の表にないorElse()メソッドは、Optionalインスタンスが空の場合に
デフォルトの値を設定することができる。

#### `get()`
Optionalクラスからのインスタンスから値を取り出す方法
```java:実装例
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.of("Hello");		
        System.out.println(optional.get());
    }
}
```
```:実装結果
Hello
```

空のOptionalのインスタンスからは値を取りだせない。
```java:実装例①
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.empty();	
        System.out.println(optional.get());
    }
}
```
```:実装結果
java.util.NoSuchElementExceptionが発生
```
```java:実装例②
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.ofNullable(null);	
        System.out.println(optional.get());
    }
}
```
```:実装結果
java.util.NoSuchElementExceptionが発生
```


#### `public static <T> Optional<T> empty()`
空のOptionalインスタンスを返します。このOptionalの値は存在しません。

型パラメータ:
T - 存在しない値の型
戻り値:
空のOptional。

```java:実装例
Optional<String> emptyOptional = Optional.empty();
```
* 上記の例では、empty()メソッドを呼び出して空のOptionalオブジェクトを生成し、それをemptyOptional変数に代入している。
* 空のOptionalオブジェクトは、値が存在しないことを明示的に表現するために使用される。
* 値が存在しない場合、Optionalのメソッドを使用して値の取得や処理を行うときに、orElse()メソッドやof()メソッドを使用することもできる。

#### `public T orElse(T other)`
存在する場合は値を返し、それ以外の場合はotherを返します。

パラメータ:
other - 存在する値がない場合に返される値、nullも可

戻り値:
値(存在する場合)、それ以外の場合はother

```java:実装例①
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.empty();		
        System.out.println(optional.orElse("Default Value"));
    }
}
```
```:実装結果
Default Value
```
* 上記の例では、orElse()メソッドを使用してデフォルト値"Default Value"を指定している。
* 値が存在しない場合には、デフォルト値が返される。

```java:実装例②
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.of("A");		
        System.out.println(optional.orElse("B"));
    }
}
```
```:実装結果
A
```

#### `public T orElseGet(Supplier<? extends T> other)`
値が存在する場合はその値を返し、そうでない場合はotherを呼び出し、その呼び出しの結果を返します。

パラメータ:
other - Supplier(値が存在しない場合は、これの結果が返される)

戻り値:
値(存在する場合)、それ以外の場合はother.get()の結果

例外:
NullPointerException - 値が存在せずotherがnullの場合

```java:実装例
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.empty();		
        System.out.println(optional.orElseGet(() -> "Default Value"));
    }
}
```
```:実装結果
Default Value
```

#### `public T orElseThrow()`
値がある場合は値を返し、そうでない場合はNoSuchElementExceptionをスローします。

戻り値:
このOptionalによって記述される非null値
例外:
NoSuchElementException - 値が存在しない場合

```java:実装例(引数なし)
import java.util.NoSuchElementException;
import java.util.Optional;
 
public class OptionalSample {
    public static void main(String[] args) {
        String str = null;
        Optional<String> value = Optional.ofNullable(str);
        try {
            str = value.orElseThrow();
            System.out.println(str);
        } catch (NoSuchElementException ex) {
            System.out.println("NoSuchElementExceptionです");
        }
    }
}
```
```:実装結果
NoSuchElementExceptionです
```

#### `public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X extends Throwable`
値が存在する場合は、その含まれている値を返し、それ以外の場合は、指定されたサプライヤによって作成された例外をスローします。

型パラメータ:
X - スローされる例外の型
パラメータ:
exceptionSupplier - スローされる例外を返すサプライヤ
戻り値:
存在する値
例外:
X - 存在する値がない場合
NullPointerException - 値が存在せずexceptionSupplierがnullの場合
X extends Throwable

```java:実装例(引数あり)
import java.util.Optional;
 
public class OptionalSample {
    public static void main(String[] args) {
        String str = null;
        Optional<String> value = Optional.ofNullable(str);
        try {
            System.out.println(value.orElseThrow(() -> new RuntimeException()));
        } catch (RuntimeException e) {
            System.out.println("RuntimeExceptionです");
        }    
    }
```
```:実装結果
RuntimeExceptionです
```

#### `public static <T> Optional<T> of(T value)`
nullでない値を保持するOptionalインスタンスを作成する。

型パラメータ:
T - 値のクラス
パラメータ:
value - 存在する値、非nullである必要がある
戻り値:
存在する値でのOptional
例外:
NullPointerException - valueがnullの場合。

```java:実装例①
String value = "Hello";
Optional<String> optional = Optional.of(value);
```
* 上記の例では、of()メソッドを使用して、valueがnullでないことを前提として値を含むOptionalインスタンスを生成し、optional変数に代入している。
```java:実装例②
String value = null;
Optional<String> optional = Optional.of(value);
```
* 上記の例では、valueがnullであるため、of()メソッドはNullPointerExceptionをスローする。
※of()メソッドを使用する際には、値がnullでないことを確認する必要がある。
値がnullである可能性がある場合には、代わりにofNullable()メソッドを
使用することが推奨される。

#### `public static <T> Optional<T> ofNullable(T value)`
指定された値がnullでない場合はその値を記述するOptionalを返し、それ以外の場合は空のOptionalを返します。

型パラメータ:
T - 値のクラス
パラメータ:
value - 記述する値(nullも可)
戻り値:
指定された値がnullでない場合は存在する値でのOptional、それ以外の場合は空のOptional

```java:実装例①
String value = "Hello";
Optional<String> optional = Optional.ofNullable(value);
```
上記の例では、ofNullable()メソッドを使用して、valueがnullでない場合は値を含むOptionalインスタンスを生成し、optional変数に代入している。

```java:実装例②
String value = null;
Optional<String> optional = Optional.ofNullable(value);
```
上記の例では、valueがnullであるため、ofNullable()メソッドは空のOptionalインスタンスを生成している。

ofNullable()メソッドを使用することで、値がnullであるかどうかを判定せずに、値を含むか空のOptionalインスタンスを作成することができる。
これは、値の存在または不在を明示的に表現するために使用される。

#### `public boolean isPresent()`
存在する値がある場合はtrueを返し、それ以外の場合はfalseを返します。

戻り値:
存在する値がない場合はtrue、それ以外の場合はfalse

```java:実装例
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.empty();
        if (optional.isPresent()) {
            System.out.println(optional.get());
        } 
    }
}
```
```:実装結果
何も表示されない
```

#### `public void ifPresent(Consumer<? super T> consumer)`
値が存在する場合は指定されたコンシューマをその値で呼び出し、それ以外の場合は何も行いません。

パラメータ:
consumer - 値が存在する場合に実行されるブロック
例外:
NullPointerException - 値が存在しconsumerがnullの場合

```java:実装例(Optionalが値を持っている)
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.of("test");
        optional.ifPresent((str)) -> System.out.println(str));
    }
}
```
```:実装結果
test
```

```java:実装例(Optionalが値を持っていない)
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.empty();
        optional.ifPresent((str) -> System.out.println(str));
    }
}
```
```:実装結果
何も表示されない
```

#### `public void ifPresentOrElse​(Consumer<? super T> action, Runnable emptyAction)`
値が存在する場合は、指定されたアクションを値とともに実行し、そうでない場合は空のベースのアクションを実行します。
値がある場合は第1引数で指定したラムダ式(Consumer型)を実行し、値がない場合は第2引数で指定したラムダ式(Runnable型)を実行する。

パラメータ:
action - 値が存在する場合、実行されるアクション
emptyAction - 値が存在しない場合、実行される空のベースのアクション
例外:
NullPointerException - 値が存在し、指定されたアクションがnullの場合、または値が存在しない場合、指定された空のアクションはnullです。

```java:実装例
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.empty();
        optional.ifPresentOrElse((str) -> System.out.println(str), () -> System.out.println("empty"));
    }
}
```
```:実装結果
empty
```

#### `public boolean isEmpty()`
値が存在しない場合はtrue、それ以外の場合falseを返します。

戻り値:
値が存在しない場合はtrue、それ以外の場合はfalse

```java:実装例
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optional = Optional.empty();
        if (optional.isEmpty()) {
            System.out.println("empty");
            return;
        } 
        System.out.println(optional.get());
    }
}
```
```:実装結果
empty
```

#### `public <U> Optional<U> map​(Function<? super T,​? extends U> mapper)`
値が存在する場合は、与えられたマッピング関数をその値に適用した結果を(ofNullable(T)のように)記述するOptionalを返します。それ以外の場合は、空のOptionalを返します。
マッピング関数がnullの結果を返した場合、このメソッドは空のOptionalを返します。

型パラメータ:
U - マッピング関数から返される値の型
パラメータ:
mapper - 存在する場合、値に適用するマッピング関数
戻り値:
値が存在する場合はマッピング関数をこのOptionalの値に適用した結果を記述するOptional、それ以外の場合は空のOptional
例外:
NullPointerException - マッピング関数がnullの場合

```java:実装例
import java.util.Optional;

public class Main {															
    public static void main(String[] args) {
        Optional<String> optionalA = Optional.of("test");
        Optional<String> optionalB = optionalA.map(str -> str.toUpperCase());
        System.out.println(optionalA.get());
        System.out.println(optionalB.get());
    }
}
```
```:実装結果
test
TEST
```

```java:実装例(空のOptionalの場合)
import java.util.Optional;

public class Main {													
    public static void main(String[] args) {
        Optional<String> optionalA = Optional.ofNullable(null);
        Optional<String> optionalB = optionalA.map(str -> str.toUpperCase());
        System.out.println(optionalB.isEmpty());
    }
}
```
```:実装結果
例外が発生せずに何も出力されない
```

#### `public <U> Optional<U> flatMap​(Function<? super T,​? extends Optional<? extends U>> mapper)`
値が存在する場合、指定されたOptional-bearingマッピング関数を値に適用した結果を返します。それ以外の場合は空のOptionalを返します。

型パラメータ:
U - マッピング関数によって返されたOptionalの値の型
パラメータ:
mapper - 存在する場合、値に適用するマッピング関数
戻り値:
値が存在する場合はOptional生成マッピング関数をこのOptionalの値に適用した結果、それ以外の場合は空のOptional
例外:
NullPointerException - マッピング関数がnullの場合、またはnullの結果を返す場合

```java:実装例(flatMapの場合)
import java.util.Optional;

public class Main {													
    public static void main(String[] args) {
        Optional<String> optionalA = Optional.of("test");
        Optional<String> optionalB = optionalA.flatMap(str -> test(str));
        System.out.println(optionalB.get());
    }
    private static Optional<String> test(String str) {
        return Optional.of(str.toUpperCase());
    }
}
```
```:実装結果
TEST
```

```java:実装例(mapの場合)
import java.util.Optional;

public class Main {													
    public static void main(String[] args) {
        Optional<String> optionalA = Optional.of("test");
        Optional<String> optionalB = optionalA.map(str -> test(str));
        System.out.println(optionalB.get());
    }
    private static Optional<String> test(String str) {
        return Optional.of(str.toUpperCase());
    }
}
```
```:実装結果
testメソッドは、String型を扱うOptionalのインスタンスへの参照を戻す。そのため、mapメソッドはこの参照を持った新しいOptionalのインスタンスを生成することになる。
つまり、Optionalの中にOptionalへの参照が入れ子で入ることになる。Optional<Optional<String>>型の値を戻すが戻り値を受け取る変数の型がOptional<String>のため、コンパイルエラー
```

### OptionalDoubleクラス
#### `public double getAsDouble()`
結果の値をdouble型で返す

### メソッド参照
```java:実装例
import java.util.List;

public class Sample {
    public static void main (String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5);
        list.forEach(System.out::println); // メソッド参照
    }
}
```

```:実行結果
1
2
3
4
5
```

### ストリームAPI
* StreamAPIとはJava SE 8で新たに導入された「データ集合の操作用API」。
* データ集合の個々のデータに対して様々な操作を順次行うことができる。
* for文などの繰り返し構文を置き換えるために用意されていない。

### ストリームを利用する理由
* コレクションや配列の全要素を同じように変換するため。
* コレクションや配列の要素の合計や平均といった統計を取るため。
* コレクションや配列の要素を何らかの条件でグルーピングするため。
* コレクションや配列の要素から条件にあったデータを検索するため。

### ストリームの処理順
コレクションが管理する順で処理される。

### Streamインタフェースの種類

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846917/2eefe8f5-4229-78a4-6022-1b0909f5475f.png)

### 中間操作
* 取り出した要素に加える処理のこと。
* ストリームオブジェクトを返す。
* メソッド呼び出しの時点で処理が実行される訳ではなく、
* 終端操作の実行時に実行される→遅延評価
* 終端操作が適応されるまで何度も(0回以上)適応することができる。

### 終端操作
* 中間操作を終えた要素の集合に対して行う最終処理のこと。
* 処理の最後に一度だけ適応することができる。
* 終端操作が適用されたストリームに対して再度ストリーム処理を適用することはできない。
→再度ストリーム処理を行おうとすると「実行時に例外がスローされる」

<table>
  <caption>【中間操作の種類】</caption>
  <thead>
    <tr>
      <th>処理を行うメソッド</th>
      <th>概要</th>
    </tr>
  </thead>
  <tr>
    <td>distinct</td>
    <td>要素の重複を除いたストリームを戻す。</td>
  </tr>
  <tr>
    <td>filter</td>
    <td>引数に指定した条件に一致する要素だけで構成されるストリームを戻す。</td>
  </tr>
  <tr>
    <td>limit</td>
    <td>ストリームの要素を、指定された数に切り詰めた結果のストリームを戻す。</td>
  </tr>
  <tr>
    <td>map</td>
    <td>指定された関数を要素に適用した結果のストリームを戻す。</td>
  </tr>
  <tr>
    <td>peek</td>
    <td>新しい結果のストリームを生成し、指定された関数を適用して戻す。</td>
  </tr>
  <tr>
    <td>skip</td>
    <td>引数で指定した最初のn個の要素を破棄し、残った要素で構成されるストリームを戻す。</td>
  </tr>
  <tr>
    <td>sorted</td>
    <td>このストリームの要素を自然順序に従ってソートした結果から構成されるストリームを戻す。</td>
  </tr>
</table>

<table>
  <caption>【終端操作の種類】</caption>
  <thead>
    <tr>
      <th>処理を行うメソッド</th>
      <th>概要</th>
    </tr>
  </thead>
  <tr>
    <td>allMatch</td>
    <td>ストリーム内のすべての要素が条件に一致するかどうかを調べる。</td>
  </tr>
  <tr>
    <td>anyMatch</td>
    <td>ストリーム内のいずれかの要素が条件に一致するどうかを調べる。</td>
  </tr>
  <tr>
    <td>collect</td>
    <td>ストリームの要素を持つコレクションを戻す。</td>
  </tr>
  <tr>
    <td>count</td>
    <td>ストリーム内の要素を数える。</td>
  </tr>
  <tr>
    <td>findAny</td>
    <td>ストリーム内に要素が残っているかどうかの結果を持つ。Optionalを戻す。</td>
  </tr>
  <tr>
    <td>findFirst</td>
    <td>ストリーム内の最初の要素を持ったOptionalを戻す。</td>
  </tr>
  <tr>
    <td>forEach</td>
    <td>ストリーム内の要素を使って繰り返し処理を実行する。</td>
  </tr>
  <tr>
    <td>max</td>
    <td>ストリーム内の最大の要素を戻す。</td>
  </tr>
  <tr>
    <td>min</td>
    <td>ストリーム内の最小の要素を戻す。</td>
  </tr>
  <tr>
    <td>noneMatch</td>
    <td>ストリーム内の要素で条件に一致するものがないかどうかを調べる。</td>
  </tr>
  <tr>
    <td>reduce</td>
    <td>ストリーム内の要素を累積的に結合していくリダクション処理を実行する。</td>
  </tr>
  <tr>
    <td>toArray</td>
    <td>ストリームの要素を含む配列を戻す。</td>
  </tr>
</table>

### 配列からストリームを作る
```java:実装例
String[] array = {"A", "B", "C"}
Stream<String> stream = Arrays.stream(array);
IntStream intStream = Arrays.stream(array);
```
※プリミティブ型(int、long、double)を扱う場合は、IntStream、LongStream、DoubleStreamを使用する

### 中間操作のメソッド
#### `Stream＜T＞ filter(Predicate<? super T> predicate)`
predicateの記述に一致するストリームを返す。

```java:実装例①
import java.util.Arrays;
import java.util.List;

public class FilterSample {
    public static void main(Stringl] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        list.stream()
        .filter(x -> x % 2 == 0)
        .forEach(System.out::println);
    }
}
```

```:実行結果
2
4
6
8
10
```

```java:実装例②
import java.util.List;
import java.util.Optional;

public class FilterSample {
    public static void main(Stringl] args) {
        List<Item> items = List.of(
                    new Item("A", 100),
                    new Item("B", 200),
                    new Item("C", 300)
                );
        Stream itemStream = items.stream();
        itemStream.filter(item -> item.getPrice() > 200)
        .forEach(System.out::println);
    }
}
```

```:実行結果
①
itemStreamのfilterメソッドに渡す引数を「item -> ((Item) item).getPrice() > 200」に置き換える。

②
変数itemStreamのデータ型をStreamからStream<Item>に置き換える
```

Stream型は型パラメータを指定しなければ、Object型のストリームとして扱われる。

#### `＜R＞ Stream＜R＞ map(Function<? super T,? extends R> mapper)`
mapperの戻り値をストリームとして返す。
集合データ内の各要素を変換するメソッド。
マップ操作では、1つの要素に対する操作で、1つの要素が返される。

```java:実装例①
import java.util.Arrays;

public class MapSample {
    public static void main(Stringl] args) {
        String[] fruits = {"apple", "orange", "banana"};
        Arrays.stream(fruits)
        .map(f -> f.toUpperCase())
        .forEach(System.out::println);
    }
}
```

```:実行結果
APPLE
ORANGE
BANANA
```

```java:実装例②
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class MapSample {
    public static void main(Stringl] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Stream<String> result = 
            list.stream().map(n -> String.valueOf(n));
    }
}
```

```:実行結果
1
2
3
4
5
```

```java:実装例③
List<String> nameList = Arrays.asList("Tanaka", "Suzuki", "Takahashi");
Stream<Integer> stream = nameList.stream().map(x -> x.length());
System.out.println(stream.collect(Collectors.toList()));
```
```:実行結果
[6, 6, 9]
```

関数型インタフェースFunctionは、引数と戻り値を別の型で指定できる。

#### `IntStream mapToInt(ToIntFunction<? super T> mapper)`
文字列を数値に変換。中間操作。

#### `＜R＞ Stream＜R＞ flatMap(Function<? super T,? extends Stream<? extends R>> mapper)`
イメージとしてはコレクションを含んだstreamを各値の一連のストリームにするメソッド。
フラットマップ操作とは、各要素を何らかのロジックで分解したり増幅したりするための操作です。従ってフラットマップ操作では、1つの要素に対する操作で、複数の要素が返される。

```java:実装例
List<String> nameList = Arrays.asList("Tanaka", "Suzuki", "Takahashi");
Stream<Object> stream = nameList.stream().flatMap(x -> Stream.of(x, x.length()));
System.out.println((stream.collect(Collectors.toList())));
```
```:実行結果
[Tanaka, 6, Suzuki, 6, Takahashi, 9]
```

#### `IntStream flatMapToInt​(Function<? super T,​? extends IntStream> mapper)`
イメージとしてはコレクションを含んだstreamを各値の一連のストリームをIntStreamに変換。


#### `Stream＜T＞ distinct()`
重複を除いたストリームを返す。

```java:実装例①
import java.util.Arrays;
import java.util.List;

public class DistinctSample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("A","B","C","A");
        list.stream()
        .distinct()
        .forEach(System.out::println);
    }
}
```

```:実行結果
A
B
C
```

```java:実装例②
public class Value {
	private String data;

	public Value(String data) {
		this.data = data;
	}

	@Override
	public int hashCode() {
		return 100;
	}

	@Override
	public boolean equals(Object obj) {
		return true;
	}

}
```
```java
import java.util.Arrays;
import java.util.List;

public class Main {
	public static void main (String[] args) {
        List<Value> list = Arrays.asList(
        		new Value("A"),
        		new Value("B"),
        		new Value("C"),
        		new Value("A")
        );
        long size = list.stream().distinct().count();
		System.out.println(size);
    }
}
```

```:実行結果
１
```

重複しているかどうかはequalsメソッドの結果がtrueになるかどうかで判定。
インスタンスが異なってもequalsメソッドによって「同値である」と判定される場合には、重複していると見なされて、取り除かれる。

#### `Stream＜T＞ sorted()`
自然順序に並べてストリームを返す。ただしストリームの要素がComparableでない場合、例外がスローされる可能性がある。

```java:実装例
import java.util.Arrays;
import java.util.List;

public class SortSample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("A", "B", "C", "A");
        list.stream()
        .sorted()
        .forEach(System.out::println);
    }
}
```
```:実行結果
A
A
B
C
```

#### `Stream＜T＞ sorted(Comparator<? super T> comparator)`
こっちはComparator型のインスタンスを直接引数に取っている。つまりcomparatorに従って並べ替えたストリームを返す。

```java:Itemクラス
class Item {
    private String name;
    public Item(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
    @Override
    public String toString() {
        return this.name;
    }
}
```
```java:実装例
import java.util.Arrays;
import java.util.List;

public class SortSample {
    public static void main(String[] args) {
        List<Item> list = Arrays.asList(
            new Item("A"),
            new Item("C"),
            new Item("B")
        );
        list.stream()
        .sorted((a, b) -> a.getName().compareTo(b.getName()))
        .forEach(System.out::println);
    }
}
```
```:実行結果
A
B
C
```

#### `Stream＜T＞ peek(Consumer<? super T> action)`
ストリーム・パイプラインの途中でどのような状態になっているかを確認したいときに使用。

```java:実装例
import java.util.Arrays;
import java.util.List;

public class PeekSample {
    public static void main(Stringl] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        list.stream()
        .map(x -> x * 3)
        .peek(x -> {
            System.out.println("debug:" + x);
        })
        .filter(x -> x % 2 == 0)
        .forEach(x -> {
            System.out.println("value:" + x);
        });
    }
}
```

```:実行結果
debug:3
debug:6
value:6
debug:9
debug:12
value:12
debug:15
```

#### `Stream＜T＞ limit(long maxSize)`
maxSize個までのストリームを返す。

```java:実装例
import java.util.Arrays;
import java.util.List;

public class LimitSample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        list.stream()
        .limit(5)
        .forEach(System.out::println);
    }
}
```

```:実行結果
1
2
3
4
5
```

#### `Stream＜T＞ skip(long n)`
nだけ要素を飛ばしたストリームを返す。

```java:実装例
import java.util.Arrays;
import java.util.List;

public class SkipSample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        list.stream()
        .skip(5)
        .forEach(System.out::println);
    }
}
```

```:実行結果
6
7
8
9
10
```

### 終端操作のメソッド
#### `collect​(Collector<? super T,​A,​R> collector)`
#### `collect​(Supplier<R> supplier, BiConsumer<R,​? super T> accumulator, BiConsumer<R,​R> combiner)`
ストリーム内の要素の集合を戻す。

```java:実装例
List<String> list = Stream.of("A", "B", "C").collect(Collectors.toList());
System.out.println(list);
```
```:実行結果
A, B, C
```

#### `void forEach(Consumer<? super T> action)`
ストリームの各要素に対して処理を行う。

```java:実装例
List.of("1", "2", "3").forEach(x -> System.out.println(x));
```
java.util.function.Consumerは、引数を受け取り、結果を戻さない処理。


```java:実装例
import java.util.List;

public class ForEachSample {
    public static void main(String[] args) {
        List<String> list = List.of("Alice", "Bob", "Charlie");
        list.stream().forEach(name -> System.out.println("Hello, " + name));
    }
}
```

```:実行結果
Hello, Alice
Hello, Bob
Hello, Charlie
```

```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class ForEachSample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("A", "B", "C", "D", "F");
        Stream<String> stream = list.stream();
        stream.forEach(x -> {
            System.out.println(x);
        });
    }
}
```
```:実行結果
ABCDE
```

```java:実装例
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

public class ForEachSample {
    public static void main (String[] args) {
        Set<String> set = new HashSet<>();
        set.add("E");
        set.add("D");
        set.add("C");
        set.add("B");
        set.add("A");
        Stream<String> stream = set.stream();
        // ハッシュコード順に出力
        stream.forEach(System.out::println);
    }
}
```

```:実行結果
ABCDE
```

#### `void forEachOrdered(Consumer<? super T> action)`
定義された実行順に従い、ストリームの各要素に対して処理を行う。

```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class ForEachOrderedlSample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("A", "B", 'C", 'D", "F");
        Stream<String> stream = list.parallelStream();
        stream.forEachOrdered(System.out::println); // 実行する度に結果が同じ
    }
}
```

```:実行結果
A
B
C
D
F
```

#### `default Stream<E> parallelStream()`
並列ストリーム

```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class ParallelSample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("A", "B", 'C", 'D", "F");
        Stream<String> stream = list.parallelStream();
        stream.forEach(System.out::println); // 実行する度に結果が異なる
    }
}
```

#### `boolean anyMatch(Predicate<? super T> predicate)`
ストリームの各要素のうち、一つでも条件を満たせばtrue

```java:実装例
boolean result = Stream.of(1,2,3,4).anyMatch(p -> p == 2);
System.out.println(result);
```

```:実装結果
「true」が一つだけ出力。
```

#### `boolean allMatch(Predicate<? super T> predicate)`
全てが条件を満たせばtrue

#### `boolean noneMatch(Predicate<? super T> predicate)`
全てが条件を満たさないのであればtrue

#### `Optional＜T＞ findFirst()`
ストリームの最初の要素を返す。Optionalについては後述

```java:実装例
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;

public class FindFirstSample {
    public static void main(String[] args) {
        String[] array = {"A", "B", "C"}
        Stream<String> stream = Arrays.stream(array);
        Optional<String> optional = stream.findFirst();
        optional.ifPresent(System.out::println);
    }
}
```
```:実行結果
A
```

```java:実装例
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;

public class FindFirstSample {
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5);
        list.parallelStream()
        .findFirst()
        .ifPresent(System.out::println);
    }
}
```
```:実行結果
1
```

```java:実装例
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class FindFirstSample {
    public static void main(String[] args) {
        Predicate<Integer> p = (num) -> {
            boolean result = num % 2 == 0;
            System.out.println(num + ":" + result);
            return result;
        };
        List<Integer> list = List.of(1, 2, 3, 4, 5);
        list.parallelStream()
        .filter(p)
        .findFirst()
        .ifPresent(System.out::println);
    }
}
```
フィルタリングの順番は毎回同じ結果にならない
findFirstメソッドが戻すのは、条件によって絞られたストリームの先頭にある２
```:実行結果
1: false
2: true
3: false
5: false
4: true
2
```

#### `Optional＜T＞ findAny()`
順序は保証されていないが(ランダム)、最初に見つけたストリームの要素を返す。

```java:実装例
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;

public class FindAnySample {
    public static void main(String[] args) {
        String[] array = {"A", "B", "C"}
        Stream<String> stream = Arrays.stream(array);
        Optional<String> optional = stream.findAny();
        optional.ifPresent(System.out::println);
    }
}
```
```:実行結果
A
```

```java:実装例
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;

public class FindAnySample {
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5);
        list.parallelStream()
        .findAny()
        .ifPresent(System.out::println);
    }
}
```
```:実行結果
ランダム出力
```

#### `Optional＜T＞ min(Comparator<? super T> comparator)`
comparatorに従って、ストリーム要素中の最小値を返す。

```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class MinSample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(98, 99, 96, 95, 97);
        Optional<Integer> result = 
                list.stream().min((a, b) -> { 
                    if (a == b) return 0;
                    if (a < b) return -1;
                    return 1;
                });
        result.ifPresent(System.out::println);
    }
}
```
```:実行結果
95
```

#### `Optional＜T＞ max(Comparator<? super T> comparator)`
comparatorに従って、ストリーム要素中の最大値を返す。

```java:実装例①
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class MaxSample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(98, 99, 96, 95, 97);
        Optional<Integer> result = 
                list.stream().max((a, b) -> { 
                    if (a == b) return 0;
                    if (a < b) return -1;
                    return 1;
                });
        result.ifPresent(System.out::println);
    }
}
```
```:実行結果
99
```

```java:実装例②
import java.util.Optional;

public class MaxSample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("B", "A", "D", "C");
        Optional<String> result = 
                list.stream().max((a, b) -> a.compareTo(b)); 
        result.ifPresent(System.out::println);
    }
}
```
```:実行結果
D
```

#### `T reduce(T identity, BinaryOperator＜T＞ accumulator)`
(初期値)identityから引数を順番に二つとって引数と同じ型を返す
accumulator（BinaryOperator）の処理を行う

```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class ReduceSample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Integer result = list.stream().reduce(10, (a, b) -> a + b)
        System.out.println(result);
    }
}
```
```:実行結果
25
```

#### `Optional＜T＞ reduce(BinaryOperator＜T＞ accumulator)`
ストリームから引数を二つとって、引数と同じ型の結果を返す。

```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class ReduceSample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Optional<Integer> result = list.stream().reduce((a, b) -> a + b)
        result.ifPresent(System.out::println);
    }
}
```
```:実行結果
15
```

#### `IntStream limit​(long maxSize)`
maxSize個までのストリームを返す。
中間操作。

#### `Stream<U> mapToObj​(IntFunction<? extends U> mapper)`
指定された関数をこのストリームの要素に適用した結果から構成される、オブジェクト値のStreamを返す。
中間操作。

#### `OptionalDouble average()`
要素の平均を求める。OptionalDoubleまたは空のOptional (このストリームが空の場合)を返す。終端操作。

#### `long count()`
ストリームの要素の個数を返す。
終端操作。

#### `IntStream range​(int startInclusive, int endExclusive)`
startInclusive(含む)からendExclusive(含まない)の範囲でステップ1でインクリメントした値を含む、順序付けされた順次IntStreamを返します。

```java:実装例
public static void main(String[] args) {
	int max = java.util.stream.IntStream.range(1, 100).max().getAsInt();
	System.out.println(max);
}
```
```:実行結果
99
```

#### `IntStream rangeClosed​(int startInclusive, int endInclusive)`
startInclusive(含む)からendInclusive(含む)の範囲でステップ1でインクリメントした値を含む、順序付けされた順次IntStreamを返す。

```java:実装例
public static void main(String[] args) {
	int max = java.util.stream.IntStream.rangeClosed(1, 100).max().getAsInt();
	System.out.println(max);
}
```
```:実行結果
100
```

#### `static IntStream iterate​(int seed, IntUnaryOperator f)`
第1引数に初期値を与え、最初はその初期値を用いて以降の中間操作 or 終端操作を行い、２回目は初期値を引数に取って第2引数の関数が呼ばれ、戻り値を用いて以降の中間操作 or 終端操作を行う。

無限順次StreamなのでStream#limit を用いて要素数を制限する必要があります。limit を忘れると例外が発生せず無限ループになる。

```java:実装例
var r = new Random();
IntStream stream = IntStream.iterate(0, a -> a + 1);
stream.limit(5)
    .mapToObj(x -> x + ",")
    .forEach(System.out::println);
```
```:実行結果
0,1,2,3,4
```

### その他
#### `Stream<T> generate​(Supplier<? extends T> s)`
引数のラムダ式が戻す値を含むランダムな整数のストリームを生成するメソッド。

```java:実装例
var r = new Random();
IntStream.generate(r::nextInt)
        .limit(10)
        .forEach(System.out::println);
```

java.util.RandomクラスのnextIntメソッドは、乱数を生成する。
staticメソッドでなく、インスタンスメソッドである。

#### `<T> Stream<T> iterate​(T seed, UnaryOperator<T> f)`
IntStream、LongStream、DoubleStream にも同様のメソッドがある。

### java.util.stream.Collector
途中経過を保持するオブジェクト

### Collectorの抽象メソッド
* supplier
* accumulator
* finisher
* combiner
* characteristics

java.util.stream.Collectorインタフェースのうち実際に行いたい処理を記述するためのものは、「accumulatorメソッド」

#### `toList`

```java:ItemType
public enum ItemType {
    BOOK, MAGAZINE, DVD
}
```
```java:Item
public class Item {
    private int id;
    private ItemType type;
    private String name;
    private int price;

    public Item(int id, ItemType type, String name, int price) {
        super();
        this.id = id;
        this.type = type;
        this.name = name;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public ItemType getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }

    @Override 
    public String toString() {
        return "Item [id=" + id + ", type=" + type
                + ", name=" + name + ", price=" + price + "]";
    }
}
```
```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CollectorsSample {
    public static void main(String[] args) {
        List<Item> list = Arrays.asList(
            new Item(1, ItemType.BOOK, "Java", 1980),
            new Item(2, ItemType.BOOK, "Lambda", 2980),
            new Item(3, ItemType.MAGAZINE, "Software", 980),
            new Item(4, ItemType.MAGAZINE, "Test", 1280)
        );

        List<Item> books = 
            list.stream()
            .filter(item -> item.getType() == ItemType.BOOK)
            .collect(Collectors.toList());

        books.forEach(System.out::println);
    }
}
```
```:実行結果
Item [id=1, type=BOOK, name=Java, price=1980]
Item [id=2, type=BOOK, name=Lambda, price=2980]
```

#### `toSet`

```java:ItemType
public enum ItemType {
    BOOK, MAGAZINE, DVD
}
```
```java:Item
public class Item {
    private int id;
    private ItemType type;
    private String name;
    private int price;

    public Item(int id, ItemType type, String name, int price) {
        super();
        this.id = id;
        this.type = type;
        this.name = name;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public ItemType getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }

    @Override 
    public String toString() {
        return "Item [id=" + id + ", type=" + type
                + ", name=" + name + ", price=" + price + "]";
    }
}
```
```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CollectorsSample {
    public static void main(String[] args) {
        List<Item> list = Arrays.asList(
            new Item(1, ItemType.BOOK, "Java", 1980),
            new Item(2, ItemType.BOOK, "Lambda", 2980),
            new Item(3, ItemType.MAGAZINE, "Software", 980),
            new Item(4, ItemType.MAGAZINE, "Test", 1280)
        );

        Set<Item> books = 
            list.stream()
            .filter(item -> item.getType() == ItemType.BOOK)
            .collect(Collectors.toSet());

        books.forEach(System.out::println);
    }
}
```
```:実行結果
Item [id=1, type=BOOK, name=Java, price=1980]
Item [id=2, type=BOOK, name=Lambda, price=2980]
```

#### `toMap`

```java:ItemType
public enum ItemType {
    BOOK, MAGAZINE, DVD
}
```
```java:Item
public class Item {
    private int id;
    private ItemType type;
    private String name;
    private int price;

    public Item(int id, ItemType type, String name, int price) {
        super();
        this.id = id;
        this.type = type;
        this.name = name;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public ItemType getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }

    @Override 
    public String toString() {
        return "Item [id=" + id + ", type=" + type
                + ", name=" + name + ", price=" + price + "]";
    }
}
```
```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CollectorsSample {
    public static void main(String[] args) {
        List<Item> list = Arrays.asList(
            new Item(1, ItemType.BOOK, "Java", 1980),
            new Item(2, ItemType.BOOK, "Lambda", 2980),
            new Item(3, ItemType.MAGAZINE, "Software", 980),
            new Item(4, ItemType.MAGAZINE, "Test", 1280)
        );

        Map<String, Item> map = 
            list.stream().collect(Collectors.toMap(
                Item::getName,
                item -> item));

        map.keySet().stream().forEach(System.out::println);
    }
}
```
```:実行結果
Java
Test
Software
Lambda
```

#### `groupingBy`
java.util.Map型の戻り値を戻す

```java:ItemType
public enum ItemType {
    BOOK, MAGAZINE, DVD
}
```
```java:Item
public class Item {
    private int id;
    private ItemType type;
    private String name;
    private int price;

    public Item(int id, ItemType type, String name, int price) {
        super();
        this.id = id;
        this.type = type;
        this.name = name;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public ItemType getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }

    @Override 
    public String toString() {
        return "Item [id=" + id + ", type=" + type
                + ", name=" + name + ", price=" + price + "]";
    }
}
```
```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GroupingSample {
    public static void main(String[] args) {
        List<Item> list = Arrays.asList(
            new Item(1, ItemType.BOOK, "Java", 1980),
            new Item(2, ItemType.BOOK, "Lambda", 2980),
            new Item(3, ItemType.MAGAZINE, "Software", 980),
            new Item(4, ItemType.MAGAZINE, "Test", 1280)
        );

        Map<ItemType, List<item>> group = 
            list.stream().collect(
                Collectors.groupingBy(Item::getType));

        System.out.println(group);
    }
}
```
```:実行結果
{
    BOOK=[
        Item [id=1, type=BOOK, name=Java, price=1980]
        Item [id=2, type=BOOK, name=Lambda, price=2980]
    ],
    MAGAZINE=[
        Item [id=3, type=MAGAZINE, name=Software, price=980]
        Item [id=4, type=MAGAZINE, name=Test, price=1280]
    ]
}
```

#### `summingInt`
値の種類ごとにグルーピング。

```java:ItemType
public enum ItemType {
    BOOK, MAGAZINE, DVD
}
```
```java:Item
public class Item {
    private int id;
    private ItemType type;
    private String name;
    private int price;

    public Item(int id, ItemType type, String name, int price) {
        super();
        this.id = id;
        this.type = type;
        this.name = name;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public ItemType getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }

    @Override 
    public String toString() {
        return "Item [id=" + id + ", type=" + type
                + ", name=" + name + ", price=" + price + "]";
    }
}
```
```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class SummingIntSample {
    public static void main(String[] args) {
        List<Item> list = Arrays.asList(
            new Item(1, ItemType.BOOK, "Java", 1980),
            new Item(2, ItemType.BOOK, "Lambda", 2980),
            new Item(3, ItemType.MAGAZINE, "Software", 980),
            new Item(4, ItemType.MAGAZINE, "Test", 1280)
        );

        Map<ItemType, Integer> group = 
            list.stream().collect(
                Collectors.groupingBy(
                    Item::getType,
                    Collectors.summingInt(Item::getPrice)));

        System.out.println(group);
    }
}
```
```:実行結果
{BOOK=4960, MAGAZINE=2260}
```

#### `partitioningBy`
条件を指定して、その条件に合致したかどうかでグループを分けることができる。
java.util.Map型の戻り値を戻す。
返されるMapには、常にfalseとtrueキーの両方のマッピングが含まれている。

```java:ItemType
public enum ItemType {
    BOOK, MAGAZINE, DVD
}
```
```java:Item
public class Item {
    private int id;
    private ItemType type;
    private String name;
    private int price;

    public Item(int id, ItemType type, String name, int price) {
        super();
        this.id = id;
        this.type = type;
        this.name = name;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public ItemType getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }

    @Override 
    public String toString() {
        return "Item [id=" + id + ", type=" + type
                + ", name=" + name + ", price=" + price + "]";
    }
}
```
```java:実装例
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class PartitioningBySample {
    public static void main(String[] args) {
        List<Item> list = Arrays.asList(
            new Item(1, ItemType.BOOK, "Java", 1980),
            new Item(2, ItemType.BOOK, "Lambda", 2980),
            new Item(3, ItemType.MAGAZINE, "Software", 980),
            new Item(4, ItemType.MAGAZINE, "Test", 1280)
        );

        Map<Boolean, List<Item>> map = 
            list.stream().collect(
                Collectors.partitioningBy(
                    item -> item.getPrice() > 1000));

        System.out.println(map);
    }
}
```
```:実行結果
false=[
    Item [id=3, type=MAGAZINE, name=Software, price=980]
],
true=[
    Item [id=1, type=BOOK, name=Java, price=1980]
    Item [id=2, type=BOOK, name=Lambda, price=2980]
    Item [id=4, type=MAGAZINE, name=Test, price=1280]
]
```

### java.util.stream.Collectors
#### `<T> Collector<T,​?,​Double> averagingDouble​(ToDoubleFunction<? super T> mapper)`
ストリームの要素をdouble型に変換し、平均を求める。
```java:実装例
double a = list.stream()
                .collect(Collectors.averagingDouble(n -> n));
                
```