stream has already been operated upon の原因と直し方
Streamは1回しか終端操作できません。中間操作の遅延評価も合わせて解説します。
エラーメッセージの読み方
Exception in thread "main" java.lang.IllegalStateException:
main- スレッド名 — mainなら起動直後の処理で発生しています
java.lang- パッケージ — java.lang なら標準の基本例外です
IllegalStateException- 例外クラス — 何が起きたか。ここを検索するのが最短です
このエラーが出る典型パターン
パターン1
1 import java.util.List; 2 import java.util.stream.Stream; 3 4 public class Main { 5 public static void main(String[] args) { 6 Stream<Integer> s = List.of(1, 2, 3).stream(); 7 System.out.println(s.count()); 8 System.out.println(s .count()); ^ 9 } 10 }
Exception in thread "main" java.lang.IllegalStateException:
stream has already been operated upon or closedexited with code 1
Streamは1回しか終端操作できません。使い回さず、必要なたびに作り直します。
直し方: s を List.of(1, 2, 3).stream() にします。
広告
広告スロット(未設定)
パターン2
1 import java.util.List; 2 3 public class Main { 4 public static void main(String[] args) { 5 List<Integer> r = List.of(1, 2, 3).stream() 6 .filter(n -> n > 1) 7 .toList ; ^ 8 System.out.println(r); 9 } 10 }
Main.java:7: error: cannot find symbol
symbol: variable toList
toListはメソッドなので括弧が要ります。古い書き方では collect(Collectors.toList()) を使います。
直し方: toList を toList() にします。
パターン3
1 import java.util.List; 2 3 public class Main { 4 public static void main(String[] args) { 5 List.of(1, 2, 3).stream().filter(n -> n > 1) ; ^ 6 System.out.println("done"); 7 } 8 }
出力: done のみ(filterは中間操作なので何も起きません)
中間操作は終端操作が呼ばれるまで実行されません。これを遅延評価と呼びます。
直し方: (空) を .forEach(System.out::println) にします。
よくある誤解
変数に入れると再利用したくなりますが、Streamは使い捨てです。コレクションとは性質が違います。
まとめ
stream has already been operated uponは上級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。