- JAVA
IllegalStateExceptionの直し方|Javaのメッセージ別一覧
java.lang.IllegalStateException は、「今の状態では、そのメソッドは呼べない」という例外です。 渡した値が悪いのではなく、呼ぶ順番やタイミングが合っていないときに出ます。原因はメッセージでほぼ決まるので、まずメッセージを見ます。
| メッセージ | 状態 | 直し方 |
|---|---|---|
stream has already been operated upon or closed |
使い終わった Stream をもう一度使った | Stream を作り直す |
Duplicate key a (attempted merging values 1 and 2) |
toMap でキーが重なった |
3つめの引数で、重なったときの扱いを決める |
No match found |
Matcher で find() / matches() の前、または一致しないのに group() |
if (m.find()) の中で group() |
Scanner closed |
閉じた Scanner を読んだ |
閉じるのは使い終わってから |
Queue full |
容量いっぱいのキューに add |
offer で false を受け取る |
| (メッセージなし) | Iterator.remove() を next() の前、または2回続けて呼んだ |
next() 1回につき remove() 1回 |
確認環境:OpenJDK 21.0.10(Linux)で再現しました(確認日 2026年10月12日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「IllegalStateExceptionの直し方|Javaのメッセージ別一覧」
stream has already been operated upon or closed
Stream は1回しか使えません。 count() や collect() などの終端操作をしたあとに、同じ Stream をもう一度使うと出ます。
Stream<String> s = Stream.of("A", "B");
System.out.println(s.count()); // 2
System.out.println(s.count()); // ← 例外
2
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
at java.base/java.util.stream.ReferencePipeline.count(ReferencePipeline.java:709)
at S1.main(S1.java:2)
直し方は、使うたびに Stream を作り直すことです。 元のデータ(リスト)を変数に持ち、そこから毎回 stream() を呼びます。
List<String> list = List.of("A", "B");
long count = list.stream().count();
List<String> upper = list.stream().map(String::toLowerCase).toList();
// 作り方が長いときは Supplier にまとめる
Supplier<Stream<String>> src = () -> list.stream().filter(x -> !x.isBlank());
long n = src.get().count();
List<String> all = src.get().toList();
Stream をフィールドや変数に入れて使い回す書き方は、この例外の元になります。持つのはリスト、Stream はその場で作る、と決めておくと防げます。
Duplicate key(toMap のキーが重なった)
Collectors.toMap は、同じキーが2回出ると例外になります。 メッセージに、重なったキーと両方の値が出ます。
record U(String name, int age) {}
Map<String, Integer> m = Stream.of(new U("a", 1), new U("a", 2))
.collect(Collectors.toMap(U::name, U::age)); // ← 例外
Exception in thread "main" java.lang.IllegalStateException: Duplicate key a (attempted merging values 1 and 2)
at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:135)
...
直し方は、3つめの引数(重なったときの扱い)を渡すことです。
| やりたいこと | 3つめの引数 | 結果 |
|---|---|---|
| あとの値を残す | (x, y) -> y |
{a=2} |
| 先の値を残す | (x, y) -> x |
{a=1} |
| 足し合わせる | Integer::sum |
{a=3} |
| 全部残す | toMap ではなく groupingBy(U::name, mapping(U::age, toList())) |
{a=[1, 2]} |
Map<String, Integer> m = Stream.of(new U("a", 1), new U("a", 2))
.collect(Collectors.toMap(U::name, U::age, (x, y) -> y)); // {a=2}
ただし、重なるはずのないキーが重なったなら、データの誤りかもしれません。 黙って片方を捨てる前に、重なったキーを確かめます。詳しくは関連記事「Java ListをMapに変換する方法 toMapのキー重複エラー対処」で扱っています。
No match found(正規表現の Matcher)
Matcher.group() は、find() か matches() で一致したあとでしか呼べません。 呼ぶ前、または一致しなかったときに group() を呼ぶと出ます。
Matcher m = Pattern.compile("(\\d+)").matcher("abc123");
m.group(1); // ← find() の前なので IllegalStateException: No match found
Matcher m = Pattern.compile("(\\d+)").matcher("abc123");
if (m.find()) {
System.out.println(m.group(1)); // 123
} else {
System.out.println("数字なし");
}
m.find(); の戻り値を見ずに group() を呼ぶと、一致しない文字列("abc")のときだけ例外になります。 テストで一致する文字列しか試していないと見落とすので、if で受けます。
Scanner closed
閉じた Scanner を読むと出ます。 よくあるのは、メソッドの中で Scanner を close() し、別のメソッドで同じ Scanner を使う形です。
Scanner sc = new Scanner(System.in);
read1(sc); // 中で sc.close() している
read2(sc); // ← IllegalStateException: Scanner closed
Scanner(System.in) を閉じると System.in も閉じます。 新しい Scanner(System.in) を作り直しても、2行目を読もうとしたところで NoSuchElementException: No line found になりました。そのため、System.in の Scanner は main で1つ作り、プログラムの最後まで閉じずに渡して使います。
Queue full
容量を決めたキュー(ArrayBlockingQueue など)がいっぱいのときに add すると出ます。
| メソッド | いっぱいのとき |
|---|---|
add(e) |
IllegalStateException: Queue full |
offer(e) |
false を返す |
put(e) |
空くまで待つ |
offer(e, 時間, 単位) |
決めた時間だけ待ち、空かなければ false |
var q = new ArrayBlockingQueue<Integer>(1);
q.add(1);
boolean ok = q.offer(2); // false(例外にならない)
いっぱいになるのがあり得る処理なら、offer の戻り値で分岐します。
Iterator.remove()(メッセージなし)
Iterator.remove() は、next() 1回につき1回だけ呼べます。 next() の前や、2回続けて呼ぶと、メッセージなしの IllegalStateException になりました。
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.isBlank()) {
it.remove(); // next() のあとに1回
}
}
// もっと短く書くなら
list.removeIf(String::isBlank);
似ているが別の例外
| 状況 | 例外 |
|---|---|
同じ Thread を2回 start() |
IllegalThreadStateException(IllegalStateException ではなく IllegalArgumentException の仲間) |
値の無い Optional に orElseThrow() |
NoSuchElementException: No value present |
shutdown() したスレッドプールに submit |
RejectedExecutionException |
変更できないリストに add |
UnsupportedOperationException |
自分で投げるとき:IllegalArgumentException との使い分け
| 例外 | 意味 | 例 |
|---|---|---|
IllegalArgumentException |
渡された値がおかしい | 年齢に -1 が渡された |
IllegalStateException |
オブジェクトの状態が、その操作に合っていない | 未接続なのに送信、確定済みの注文を変更 |
public void ship() {
if (status != Status.PAID) {
throw new IllegalStateException("未入金の注文は出荷できません: id=" + id + ", status=" + status);
}
status = Status.SHIPPED;
}
メッセージには「何をしようとして、今どの状態だったか」を入れると、ログだけで原因が分かります。IllegalArgumentException の使い分けは、関連記事「Java IllegalArgumentExceptionの使い分け早見表」で扱っています。
よくある質問
Q. メッセージがなく、原因が分かりません。
A. スタックトレースの1行目の at(例外を投げたメソッド)を見ます。Itr.remove なら Iterator、AbstractPipeline なら Stream、Matcher なら正規表現です。
Q. Stream をデバッグで peek や count して確かめたら、例外になりました。
A. 確かめるために終端操作をすると、その Stream は使い終わりになります。確かめるときも、元のリストから新しく Stream を作ります。
Q. toMap のキー重複は、例外にしておくべきですか。
A. 重ならない前提のデータ(主キーなど)なら、例外のままのほうが誤ったデータに気づけます。重なるのが当たり前のデータなら、3つめの引数で扱いを決めます。
Q. 例外を catch して無視してもいいですか。
A. 状態の食い違いを隠すことになるので、おすすめしません。呼ぶ順番を直すか、find() や offer() のように結果を返すメソッドに変えます。
まとめ
- 「今の状態では呼べない」という例外。原因はメッセージで決まる
stream has already been operated upon or closedは Stream の使い回し。元のリストから毎回作るDuplicate keyはtoMapのキー重複。3つめの引数で扱いを決めるNo match foundはfind()の結果を見ずにgroup()。if (m.find())で受ける- 自分で投げるなら、値の誤りは IllegalArgumentException、状態の誤りは IllegalStateException
参考・出典
確認日はいずれも 2026年10月12日です。
- Java SE 21 API「IllegalStateException」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/IllegalStateException.html
- Java SE 21 API「java.util.stream」(Stream operations and pipelines):https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/package-summary.html
- Java SE 21 API「Collectors.toMap」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/Collectors.html
- Java SE 21 API「Matcher」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Matcher.html
- Java SE 21 API「BlockingQueue」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/BlockingQueue.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「IllegalStateExceptionの直し方|Javaのメッセージ別一覧」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。