【Java】コレクションを扱う上で覚えておきたいStream API

## ストリームAPIとは
コレクション（集合体）をより扱いやすくするためのものです。使用する流れとして以下の通りです。

1. コレクションからstreamを取得
2. streamに対して「中間操作」を実行。コレクションの中身を都合よく変換
3. 「終端操作」で変換したコレクションの中身に対して処理を適用する

:::note warn
ラムダ式を使用していくのでラムダ式の使い方がわからない方は以下の記事でラムダ式について学ぶことをお勧めします。
:::

https://qiita.com/110shun/items/07f96b571532c18d97c0


## ストリームを取得するためメソッド
#### Collectionインターフェースのstreamメソッド
デフォルトメソッドとして実装されており、ListやSetといったCollectionのサブインターフェースでも利用できます。

```Sample.java
import java.util.List;

public class Sample {
	public static void main(String[] args) throws Exception{
		List <Integer> list = List.of(1,2,3);
		list.stream().forEach(System.out::println);
	}
}
```
```
1
2
3
```

#### Arraysクラスのstreamメソッド
配列からストリームをを作るにはArrysクラスのstreamメソッドを使います。使い方としては４つのパターンがあります。

#### 配列が参照型の場合


```Sample.java

import java.util.Arrays;
import java.util.stream.Stream;

public class Sample {
	public static void main(String[] args) {
		String[] array = {"A","B","C"};
		Stream <String>stream = Arrays.stream(array);
		stream.forEach(System.out::println);
	}
```
```
A
B
C
```

#### 配列がint型の場合


```Sampl.java
import java.util.Arrays;
import java.util.stream.IntStream;

public class Sample {
	public static void main(String[] args) {
		int[] array = {1,2,3};
		IntStream intStream = Arrays.stream(array);
		intStream.forEach(System.out::println);
	}
}
```
```
1
2
3
```

#### 配列がLong型の場合
```Sample.java
import java.util.Arrays;
import java.util.stream.Stream;

public class Sample {
	public static void main(String[] args) {
		long l = 19700820;
		Long[] array = {l,l,l};
		Stream<Long> stream = Arrays.stream(array);
		stream.forEach(System.out::println);
	}
}
```
#### 配列がDouble型の場合

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

public class Sample {
	public static void main(String[] args) {
		Double[] array = {0.1,0.2,0.3};
		Stream<Double> stream = Arrays.stream(array);
		stream.forEach(System.out::println);
	}
}
```
```
0.1
0.2
0.3
```

## 中間操作
#### filterメソッド
Predicate型の引数を受け取り、ラムダ式で指定された条件に一致するかストリーム内の要素に絞り込みます。

```Sample.java
import java.util.List;

public class Sample {
	public static void main(String[] args) {
		List <Integer> list =  List.of(1,2,3,4,5,6,7);
		list.stream()
		.filter(x -> x<5)
		.forEach(System.out::print);
	}
}
```
```
1234
```

#### distinctメソッド
ストリーム内の要素の重複を取り除きます。

```Sample.java
import java.util.List;

public class Sample {
	public static void main(String[] args) {
		List <Integer> list =  List.of(1,2,1,4,1,6,1);
		list.stream()
		.distinct()
		.forEach(System.out::print);
	}
}
```
```
1246
```

#### limitメソッド
数を絞り込むためのメソッドです。

```Sample.java
import java.util.List;

public class Sample {
	public static void main(String[] args) {
		List <Integer> list =  List.of(1,2,1,4,1,6,1);
		list.stream()
		.limit(3)
		.forEach(System.out::print);
	}
}
```

```
121
```

#### skipメソッド
引数で指定した数以降の要素を取り出すメソッドです。

```Sample.java
import java.util.List;

public class Sample {
	public static void main(String[] args) {
		List <Integer> list =  List.of(1,2,1,4,1,6,1);
		list.stream()
		.skip(3)
		.forEach(System.out::print);
	}
}
```
```
4161
```

#### sortedメソッド
ストリーム内の要素を並び替えるメソッドです。

```Sample.java
import java.util.List;

public class Sample {
	public static void main(String[] args) {
		List <String> list =  List.of("C","D","E","A","B");
		list.stream()
		.sorted()
		.forEach(System.out::print);
	}
}
```
```
ABCDE
```
#### mapメソッド
ストリームの要素に対して何らかの処理を加えたい時に使用するメソッドです。

```Sample.java
import java.util.List;

public class Sample {
	public static void main(String[] args) {
		List <String> list =  List.of("apple","banana","orange");
		list.stream()
		.map(x -> x.length())
		.forEach(System.out::print);
	}
}
```
```
566
```
#### peekメソッド
終端操作までの間にどのような状態になっているか確認したい時に使用するメソッドです。
主にデバック時に使用します。

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

public class Sample {
	public static void main(String[] args) {
	List<Integer> list = Arrays.asList(1,2,3,4,5);
	list.stream()
	.peek(x -> {
		System.out.println("debug:" + x);
	})
	.filter(x -> x % 2 == 0) //偶数のみ抽出
	.forEach(x->{
		System.out.println("value:" +x);
	});

	}
}
```
```
debug:1
debug:2
value:2
debug:3
debug:4
value:4
debug:5
```

## 終端操作

#### forEach
ストリーム内の要素をコレクショが保持している順に処理する

#### findFirstメソッド
ストリーム内の最初の要素を取り出すメソッドです。
```Sample..java
import java.util.Arrays;
import java.util.stream.Stream;

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

#### reduceメソッド
値を累積的に結合していく関数を実行するためのものです。

```Sample.java
import java.util.List;
import java.util.Optional;

public class Sample {
	public static void main(String[] args) {
		List<Integer> list = List.of(1,2,3,4,5);
		Optional<Integer>result=list.stream().reduce((a,b) -> a + b);
		result.ifPresent(System.out::print);
	}
}
```
```
15
```

#### maxメソッド
最大値を戻します。

```Sample.java
import java.util.List;
import java.util.Optional;

public class Sample {
	public static void main(String[] args) {
		List<Integer> list = List.of(1,2,3,4,5);
		Optional <Integer> result = list.stream().max((x,y)->{
					if(x==y) return 0;
					if(x<y) return -1;
					return 1;
		});
		result.ifPresent(System.out::println);
	}
}
```
```
5
```

#### minメソッド
最小値を戻します。

```Sample.java
import java.util.List;
import java.util.Optional;

public class Sample {
	public static void main(String[] args) {
		List<Integer> list = List.of(1,2,3,4,5);
		Optional <Integer> result = list.stream().min((x,y)->{
		  if(x==y) return 0;
		  if(x<y) return -1;
		  return 1;
		});
		result.ifPresent(System.out::println);
	}
}
```
```
1
```
:::note warn
終端操作は１回しか呼び出せません。
２回目を呼び出すとillegalStateExceptionがスローされます。
:::


## 参考
・徹底攻略Java SE 11 Gold問題集

https://qiita.com/takumi-n/items/369dd3fcb9ccb8fcfa44