SimpleDateFormatがスレッドアンセーフであることをstreamを使って検証する

#導入
こんにちは。けちょんです。
**皆さん、SimpleDateFormatとstream使っていますか？**
ニッチですね。私はstreamが大好きです。
今回はSimpleDateFormatがスレッドアンセーフであることを検証します。

#準備
まず、Date型のオブジェクトを用意します。

```java
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");

Calendar day1 = Calendar.getInstance();
day1.set(2020, 0, 31, 0, 0, 0);
Calendar day2 = Calendar.getInstance();
day2.set(1995, 3, 6, 0, 0, 0);
```

では、リストに詰めます。

```java
for (int i = 0; i < 10; i++) {
	// リストにDateオブジェクトを20個詰める
	list.add(day1.getTime());
	list.add(day2.getTime());
}
```

まずは並列実行せずに、処理します。

```java
list.stream().map(date -> sdf.format(date)).forEach(System.out::println);
// 各要素を順にStringに変換し、出力
```

全貌は以下です。

```java
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");

Calendar day1 = Calendar.getInstance();
day1.set(2020, 0, 31, 0, 0, 0);
Calendar day2 = Calendar.getInstance();
day2.set(1995, 3, 6, 0, 0, 0);
List<Date> list = new ArrayList<>(); // リストの作成

for (int i = 0; i < 10; i++) {
	// リストにDateオブジェクトを詰める
	list.add(day1.getTime());
	list.add(day2.getTime());
}

list.stream().map(date -> sdf.format(date)).forEach(System.out::println);
```

#シングルスレッドで実行
```
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
```
問題無さそうですね。

#マルチスレッドで実行
streamはparallel()を中間操作に追加するだけで、並列処理してくれます。

```java
list.stream().map(date -> sdf.format(date)).forEach(System.out::println);
```

では実行してみましょう！

```
2020/01/31 12:00:00
1995/01/31 12:00:00 // なにこれ
1995/04/06 12:00:00
2020/01/31 12:00:00
2020/01/31 12:00:00
2020/01/31 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/06 12:00:00
2020/01/31 12:00:00
1995/04/31 12:00:00 // なにこれ
```
想定外の日付が一部出力されましたね。
スレッドアンセーフであることが確認できました。

#対策
各スレッドで、SimpleDateFormatオブジェクトを生成しても良いです。
基本的にはJava8から実装されたDate And Time APIを使用するのが良いでしょう。

##DateTimeFormatterを使用した実装

```java
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss");

LocalDateTime today = LocalDateTime.now();
LocalDateTime birthDay = LocalDateTime.of(1995, 4, 6, 12, 0, 0);

List<LocalDateTime> list = new ArrayList<>();

for (int i = 0; i < 10; i++) {
	// リストにDateオブジェクトを詰める
	list.add(today);
	list.add(birthDay);
}

list.stream().parallel().map(date -> dtf.format(date)).forEach(System.out::println);
```
```
2020/01/31 09:33:20
1995/04/06 12:00:00
1995/04/06 12:00:00
2020/01/31 09:33:20
1995/04/06 12:00:00
2020/01/31 09:33:20
2020/01/31 09:33:20
2020/01/31 09:33:20
2020/01/31 09:33:20
2020/01/31 09:33:20
2020/01/31 09:33:20
1995/04/06 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
1995/04/06 12:00:00
2020/01/31 09:33:20
2020/01/31 09:33:20
1995/04/06 12:00:00
1995/04/06 12:00:00
```
大丈夫そうですね。

#まとめ
Java8以降はDate And Time APIを使用しましょう