迭代器本身不抛异常,真正需处理的是第三方SDK在next()/hasNext()中抛出的非标准异常;应为每次next()单独try-catch Throwable,按类型分级处理,并封装SafeIterator适配层统一异常策略。

迭代器本身不抛出异常,也不参与异常捕获——它只是遍历容器的工具。真正需要处理的是:在用迭代器遍历第三方 SDK 返回的数据集(如 Iterator<Record>)时,SDK 内部可能在 next() 或 hasNext() 中抛出非标准异常(比如未继承 RuntimeException 的自定义 UncheckedException,或直接抛出 Error 子类)。这类异常往往没被文档说明,且类型混乱,不能靠常规 catch (Exception e) 安全覆盖。
识别并隔离非标准异常源头
第三方 SDK 的数据清洗逻辑常封装在迭代器实现中,next() 可能触发解析、校验、转换等操作。一旦出错,它可能:
- 抛出未声明的运行时异常(如
com.thirdparty.DataCorruptException,但该类未继承RuntimeException,却也未被throws声明) - 包装原始异常后抛出
Throwable或Error(例如ServiceConfigurationError) - 在
hasNext()中静默失败,导致后续next()突然抛出空指针或非法状态
用 try-catch 包裹单次 next() 调用
不要把整个 while 循环包进一个大 try 块。应将异常控制粒度缩小到每次 next(),确保单条记录失败不影响其余数据:
- 在循环体内对
iterator.next()单独加 try-catch - 捕获
Throwable(仅在此场景下合理),因为 SDK 可能抛出Error或无继承关系的异常类 - 对捕获到的异常做类型判断,区分可恢复(跳过当前记录)、需告警(日志+计数)、应中断(如配置级错误)三类
示例:
try {Record record = iterator.next();
process(record);
} catch (Throwable t) {
if (t instanceof OutOfMemoryError || t instanceof StackOverflowError) {
throw t; // JVM 级错误,不捕获
} else if (isDataLevelException(t)) {
log.warn("跳过脏数据记录,原因:{}", t.getMessage());
continue;
} else {
log.error("SDK 迭代器未知异常,终止清洗", t);
throw new DataPipelineException("第三方 SDK 迭代异常", t);
}
}
封装安全迭代器适配层
避免在业务代码中重复写 try-catch。可封装一个 SafeIterator<T>,内部代理原始迭代器,并统一处理异常策略:
- 构造时接收原始
Iterator<T>和异常处理器(如BiConsumer<Throwable, Integer>,含失败序号) -
hasNext()不抛异常,只返回布尔值;若底层调用失败,缓存异常并返回false -
next()检查是否已发生底层异常,有则直接抛出包装后的WrappedSdkException - 提供
getFailureCount()和getLastFailure()供监控
配合线程上下文与日志增强可观测性
SDK 异常缺乏上下文,需人工补全:
- 在捕获异常时,记录当前迭代序号、原始输入批次 ID、线程名(建议用
ThreadFactory命名清洗线程为cleaner-xxx) - 使用 MDC(如 Logback)注入
recordId或batchId,让日志自动携带关键字段 - 对高频出现的异常类型(如
ParseException)建立白名单,单独统计并告警,而非一律视为错误

















