Iterator.remove() 只能调用一次,重复调用抛 IllegalStateException;HttpServletRequest 的 getReader() 与 getInputStream() 互斥;HttpServletResponse.getWriter() 在响应已提交后调用会失败;@Transactional 中手动 flush 后误操作 EntityManager 也会触发该异常。

Iterator.remove() 在遍历中调用两次会直接抛 IllegalStateException
Java 的 Iterator 是“一次一删”设计:调用 remove() 后,内部状态标记为“已删除”,此时再调用一次就会触发 IllegalStateException。这不是 bug,是规范强制要求——避免重复移除导致集合不一致。
常见错误现象:IllegalStateException: Iterator already removed element(不同 JDK 版本提示略有差异,但都指向同一状态)
- 只允许在
next()返回元素后、且尚未调用过remove()时调用一次remove() - 如果中间穿插了其他
next(),必须重新对新元素做判断,不能复用上一轮的remove() - 多线程环境下即使单次调用也危险:其他线程修改集合会触发
ConcurrentModificationException,而非IllegalStateException,别混淆
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if ("skip".equals(s)) {
it.remove(); // ✅ 正确
// it.remove(); // ❌ 这里立刻抛 IllegalStateException
}
}
HttpServletRequest.getReader() / getInputStream() 二选一失败引发 IllegalStateException
Servlet 容器(如 Tomcat)规定:请求体只能被读取一次。一旦调用了 getReader(),再调用 getInputStream();或反过来,都会触发 IllegalStateException: getReader() has already been called for this request 或类似提示。
典型使用场景:过滤器中尝试统一解析 JSON body,又没注意读取方式冲突。
立即学习“Java免费学习笔记(深入)”;
-
getReader()返回BufferedReader,适合文本(如 JSON、表单) -
getInputStream()返回ServletInputStream,适合二进制(如文件上传、图片) - 两者互斥,容器内部共享同一个底层流指针,二次调用会检测到“已消费”状态
- Spring MVC 的
@RequestBody底层其实也走这两者之一,自定义过滤器里提前读取时务必统一路径
HttpServletResponse.getWriter() 在 response 已提交后调用
当响应头已发送(response.isCommitted() == true),再调用 getWriter() 或 getOutputStream(),会抛 IllegalStateException: getWriter() has already been called 或 Response already committed 类错误。
这通常不是代码直接写的错,而是流程控制失当:
- 异步处理中未检查
isCommitted()就试图写响应(比如超时回调里强行输出) - Filter 或 Interceptor 中捕获异常后想“补救性”写错误页,但 response 实际早已 flush
- 某些框架(如旧版 Struts)自动 commit 响应的时机不透明,容易误判
- JDK 17+ 对已提交响应的 writer 获取做了更严格校验,老代码升级后更容易暴露
Spring 中 @Transactional 方法内手动刷新 EntityManager 导致状态冲突
在 Spring 管理的事务中,若手动调用 EntityManager.flush() 后又执行了脏检查外的修改(比如改了托管实体字段但没触发 dirty check),再交由 Spring 提交时可能因状态不一致抛 IllegalStateException,典型提示如 Transaction is not active 或 EntityManager is closed —— 表面看是关闭,实则是 flush 后事务上下文被意外清理或重置。
-
flush()强制同步内存状态到 DB,但不提交事务;之后仍可继续操作 - 但如果 flush 后又调用了
clear()或close(),EntityManager 进入不可用状态,后续任何操作都会触发异常 - 使用
OpenSessionInView模式时,flush 和 view 渲染顺序不当,也可能让 session 在视图渲染中途被关闭 - 推荐做法:让 Spring 全权管理 flush 时机(默认 commit 前 flush),除非有强一致性要求才显式调用,且确保 flush 后不再干预 EntityManager 生命周期










