stream处理文件元素时,应通过校验(如numberutils.iscreatable)、optional封装(safeparseint)、默认值兜底(orelse)及collector防null等手段,使数字解析失败可预期、不中断流、不抛异常。

用 Stream 处理文件元素(如读取 CSV 行、日志字段、配置项等)时,若其中混入非数字字符串(如 "N/A"、""、"abc"),直接调用 Integer::parseInt 或 Integer::valueOf 会立即抛 NumberFormatException,导致整个流中断。关键不是“避免转换”,而是让转换失败可预期、可兜底、不崩溃。
过滤或映射前先校验数字格式
别在 map() 里硬转,先用正则或工具方法筛出合法数字字符串:
- 用
String::matches("\d+")判断是否为纯非负整数(注意:不支持负号、空格、科学计数法) - 更稳妥用
NumberUtils.isCreatable(str)(Apache Commons Lang),它能识别"-123"、" 456 "、"+789" - 示例:
lines.filter(s -> NumberUtils.isCreatable(s.trim())).map(s -> Integer.parseInt(s.trim()))
用 Optional 封装转换逻辑,失败返回空而非异常
把“字符串 → 数字”封装成一个可选操作,让流自然跳过坏数据:
- 写一个工具方法:
static Optional<integer> safeParseInt(String s) { try { return Optional.of(Integer.parseInt(s.trim())); } catch (NumberFormatException e) { return Optional.empty(); } }</integer> - 流中使用:
lines.map(this::safeParseInt).filter(Optional::isPresent).map(Optional::get) - 优势:不中断流、不丢上下文、便于后续统计失败条数(加
peek记录日志)
统一兜底默认值,避免 Optional 嵌套过深
如果业务允许缺失值用默认数(如 0、-1),可用 orElse 简化链路:
-
lines.map(s -> safeParseInt(s).orElse(0))—— 直接得到Stream<integer></integer> - 慎用
orElseThrow():除非你明确要让某类错误暴露为运行时异常 - 注意:默认值需语义合理(例如状态码用
0可能和正常值冲突,建议用-999等哨兵值)
结合 Collector 做聚合时预防空值穿透
当用 collect(Collectors.toMap(...)) 或 groupingBy 时,value 或 key 若来自解析结果,null 仍可能引发 NPE:
- 避免:
.collect(Collectors.toMap(line -> line, line -> Integer.parseInt(line))) - 改为:
.collect(Collectors.toMap(line -> line, line -> safeParseInt(line).orElse(-1))) - 或用
Collectors.collectingAndThen后置校验:collectingAndThen(toList(), list -> list.stream().map(...).toList())











