回答編集履歴

2

swordoneさんのdata.forEach()は副作用ではないという意見に同意

2020/02/07 04:40

投稿

xebme
xebme

スコア1109

answer CHANGED
@@ -27,9 +27,8 @@
27
27
 
28
28
  > foreachではdataが書き換わってしまうという事ぐらいでしょうか?(stream api は新しいcollectionに対しての操作という認識)
29
29
 
30
- どちらも元のデータを書き換える副作用があります。Collectionの更メソッド呼ぶから。
30
+ data.stream().forEach()は元のデータを書き換える副作用があります(しい出力ず終端処理で自己更新する)(*swordoneさんのdata.forEach()は副作用ではないという意見に同意。以後、Stream処理が入力を汚すという意味で「副作用」を使います)
31
31
 
32
-
33
32
  **map/peek**
34
33
 
35
34
  さらに副作用のある例を2つ示します。map()は戻り値を返す必要があります。peek()は戻り値なしです。

1

訂正とStreamの利用を追記

2020/02/07 04:40

投稿

xebme
xebme

スコア1109

answer CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  > ① stream api と foreachの違いはなんでしょうか?
20
20
 
21
- forEach()はコレクションストリームの両方にあります。どちらも引数にConsumerを取ります。違いは[The Difference Between Collection.stream().forEach() and Collection.forEach()](https://www.baeldung.com/java-collection-stream-foreach)に書かれているとおり、コレクションが内部的にIteratorを使用するのに対してStreamはListを順にトラバースします。Iteratorを書き換えると処理順が変わります。この例でその必要はなさそうです。
21
+ forEach()はCollectionStreamの両方にあります。どちらも引数にConsumerを取ります。違いは[The Difference Between Collection.stream().forEach() and Collection.forEach()](https://www.baeldung.com/java-collection-stream-foreach)に書かれているとおり、Collectionが内部的にIteratorを使用するのに対してStreamはListを順にトラバースします。Iteratorを書き換えると処理順が変わります。この例でその必要はなさそうです。
22
22
 
23
23
  ```Java
24
24
  data.forEach(e->e.add(999));
@@ -27,25 +27,26 @@
27
27
 
28
28
  > foreachではdataが書き換わってしまうという事ぐらいでしょうか?(stream api は新しいcollectionに対しての操作という認識)
29
29
 
30
- どちらも元のデータを書き換える副作用があります。
30
+ どちらも元のデータを書き換える副作用があります。Collectionの更新メソッドを呼ぶから。
31
31
 
32
32
 
33
33
  **map/peek**
34
34
 
35
35
  さらに副作用のある例を2つ示します。map()は戻り値を返す必要があります。peek()は戻り値なしです。
36
36
 
37
- > ③ stream apiを使うとしたら、どのように元のListにキャストするのでしょうか?
38
-
39
- すでに(List<Integer>)のStreamになっているのでキャストできません。`.collect(Collectors.toList())`で、新しく外側のListを作ってもとの中身を格納します。
40
-
41
37
  ```Java
42
38
  data.stream().map(e -> {e.add(999);return e;}).collect(Collectors.toList());
43
39
  data.stream().peek(e -> e.add(999)).collect(Collectors.toList());
44
40
  ```
45
41
 
42
+ > ③ stream apiを使うとしたら、どのように元のListにキャストするのでしょうか?
43
+
44
+ すでに(List<Integer>)のStreamになっているのでキャストできません。`.collect(Collectors.toList())`で、新しく外側のListを作ってもとの中身を格納します。
45
+
46
+
46
47
  **すべてを作り直す**
47
48
 
48
- 中身をすべてコピーして新しく作るやり方です。入力はそのまま残り、副作用はありません。
49
+ 中身をすべてコピーして新しく作るやり方です。入力はそのまま残り、副作用はありません。この方法だと`data`を作る時に`ArrayList::new`が不要になります。
49
50
 
50
51
  ```Java
51
52
  data.stream()
@@ -57,4 +58,8 @@
57
58
 
58
59
  - Stream/Collectionは、どちらも副作用がある
59
60
  - Streamは、filter/mapなどのメソッドチェーンが使えるので、データを加工するならStreamを使う
60
- - Collectionは、Iteratorを書き換えて、処理の順番を変えることができる
61
+ - Collectionは、Iteratorを書き換えて、処理の順番を変えることができる
62
+
63
+ **Streamの利用**
64
+
65
+ Streamhは並行処理で利用することがあり、副作用が起きないようにimmutableなコレクションを扱うほうがよい。また、immutableにしておけば、誤ってコレクションを更新しても例外が発生する。