【Java】Stream API - ストリーム生成

#Steam APIとは？
* **繰り返し処理**をサポートするライブラリ
* コレクション、配列、ファルなどデータの集合（データソース）から要素を取り出し処理の流れ（Stream）に引き渡す

#Stream API基本
* データソースからの**ストリーム生成**
* **中間処理**（抽出・加工など）
    * 戻り値は`Stream<T>`
* **終端処理**（出力・集計など）
    * 終端処理のタイミングでストリーム一連の処理が実行（遅延処理）
* 中間/終端処理は型合致する標準ライブラリをメソッド参照可能
* **メソッドチェーン**：ストリーム生成から中間処理/終端処理を`.`演算子で連結できる

```java
import java.util.ArrayList;
import java.util.Arrays;

public class StreamBasic {

//データソース準備
  public static void main(String[] args) {
    var list = new ArrayList<String>(Arrays.asList("ant", "elephant", "hamster"));

/*ストリームによる処理
あらかじめ用意されたリストっからストリーム生成
ArrayList<String>を元にしているので
streamメソッドもStream<String>オブジェクトを返す
*/
    list.
      stream().
      /*中間処理
      filterメソッドで文字数3以上を取り出し、mapで大文字変換
      戻り値はStream<T>
      */
      filter(s -> s.length() > 3).
      map(String::toUpperCase).
      /*終端処理
      forEachメソッドで与えられた値をSystem.out
      */
      forEach(System.out::println);//ELEPHANT HAMSTER
  }
}
```

##ストリーム生成
### **コレクション、配列からストリーム生成**
* リスト、配列、マップ内容をストリーム処理で出力できる

```java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class StreamBasic2 {

//リスト
  public static void main(String[] args) {
    var list = new ArrayList<String>(Arrays.asList("ant", "elephant", "hamster"));
    list.stream().forEach(System.out::println);
    // list.parallelStream().forEach(System.out::println);
    System.out.println("---------------");

//配列
    var data = new String[] { "バラ", "あさがお", "チューリップ" };
    Arrays.stream(data).forEach(System.out::println);
    System.out.println("---------------");

//マップ
    var map = new HashMap<String, String>(
        Map.of("orange", "みかん", "apple", "りんご", "strawberry", "いちご"));
    map.entrySet().stream().forEach(System.out::println);
  }
}
```

* **parallelStream**streamメソッドの並列版
    * リストマップのコレクションであればstreamをparallelStreamに変えたら並列処理可能になる
    * **`list.parallelStream().forEach(System.out::println)`**

### **引数/ラムダ式からストリーム生成**
* Stream生成のためのファクトリーメソッド

####**ofメソッド**
* **指定された可変長引数をストリームに変換**

```java
import java.util.stream.Stream;

public class StreamOf {
  public static void main(String[] args) {
    var stream = Stream.of("first", "second", "third");
    stream.forEach(System.out::println); //first, second, third
  }
}
```
####**generateメソッド**
* **指定されたラムダ式の戻り値でストリーム生成**
    * ex: 1~100の乱数を生成、ストリーム化
    * 無限にストリーム生成するので中間/終端処理で明示的に中断
    * 以下の例ではlimit(10)で先頭10件のみ処理している
    * アプリで乱数ストリーム生成するときは`Random.intsメソッド`

```java
import java.util.Random;
import java.util.stream.Stream;

public class Main {
public static void main(String[] args) throws Exception {

    var stream = Stream.generate(() -> {
      var r = new Random();
      return r.nextInt(100);
    });
    stream.limit(10).forEach(System.out::println);
    //46 24 42 80 61 67 69 22 85 1
  }
}
```

####**iterateメソッド**
* **指定された初期値とラムダ式でストリーム生成**
    * 最初に初期値、以降は直前の結果が渡される
    * 以下の例では1を初期値として2倍ずつ増やした値を生成

```java
import java.util.stream.Stream;
public class Main {
  public static void main(String[] args) {
    var stream = Stream.iterate(1, (num) -> {
      return num * 2;
    });
    stream.limit(10).forEach(System.out::println);
    //4 8 16 32 64 128 256 512
    }
}
```

####**builderメソッド**
* ストリーム組み立てるためのStream.Builderオブジェクト誠意せい

```java
import java.util.stream.Stream;
public class Main {
  public static void main(String[] args) {
    var builder = Stream.builder()
        .add("Munchkin")
        .add("Siamese")
        .add("Persian");
      builder.build().forEach(System.out::println); 
      //Munchkin
      //Siamese
      //Persian
  }
}
```

####**concatメソッド**
* **複数のストリームを絵for都合して一個のストリームにまとめる**

```java
import java.util.stream.Stream;
public class Main {
  public static void main(String[] args) {

    var stream1 = Stream.of("Munchkin", "Siamese", "Persian");
    var stream2 = Stream.of("Corgi", "Poodle", "Shiba");
    Stream.concat(stream1, stream2).forEach(System.out::println);
    // Munchkin Siamese Persian 
    // Corgi Poodle Shiba
  }
}
```

##**基本型ストリームの生成**
* 基本型に特化した**IntStream/LongStream/DoubleStream**
* **of/generate/iterate/builderファクトリーメソッド**使える
* IntStream/LongStreamでは**rangeメソッド**が使える

```java
//上限値あhストリームに含まれない
import java.util.stream.IntStream;
public class Main {
  public static void main(String[] args) {
    IntStream.range(10, 20)
      .forEach(System.out::println); //10 11 12 13 14 15 16 17 18 19
  }
}
```

* 上限も含めたい場合、**rangeClosedメソッド**

```java
import java.util.stream.IntStream;
public class Main {
  public static void main(String[] args) {
    IntStream.rangeClosed(10, 20)
     .forEach(System.out::println); //10 11 12 13 14 15 16 17 18 19 20
  }
}
```