NumberFormatException是运行时异常,表示字符串无法解析为数值类型;应单独捕获而非用Exception笼统处理,以区分用户输入错误与系统逻辑错误,并记录原始字符串便于排查。

NumberFormatException 是什么,为什么不能 catch (Exception e)
NumberFormatException 是 RuntimeException 的子类,表示字符串无法被解析为指定数值类型(如 Integer.parseInt("abc") 会直接抛出)。它不是受检异常,所以编译器不强制要求 try-catch;但一旦发生,程序会中断当前执行流。
用 catch (Exception e) 捕获看似省事,实际掩盖了问题本质:你本该区分「用户输错」和「系统内部逻辑错误」。比如 Integer.parseInt(request.getParameter("id")) 失败,应返回 400 错误,而不是吞掉异常继续跑。
- 只捕获
NumberFormatException,避免误吞其他异常(如NullPointerException) - 不要在工具方法里静默返回默认值(如
parseInt(s) → 0),这会让调用方误以为解析成功 - 日志中必须记录原始字符串,否则无法排查是前端传参问题还是数据污染
String 转 int 的安全写法(Java 8+)
Java 8 引入了 Optional,适合封装「可能失败的转换」。比起自己写 if-else 判断空/格式,用 Optional 更明确表达意图。
public static OptionalsafeParseInt(String s) { if (s == null || s.trim().isEmpty()) { return Optional.empty(); } try { return Optional.of(Integer.parseInt(s.trim())); } catch (NumberFormatException e) { return Optional.empty(); } }
-
s.trim()必须加,否则" 123 "会成功,但" 12a "仍失败——空格干扰常被忽略 - 别用
StringUtils.isNumeric()预判,它对"-123"或"+456"返回 false,但Integer.parseInt支持 - 如果需要默认值,由调用方决定:
safeParseInt(s).orElse(-1),而非在解析方法里硬编码
批量解析时怎么避免单点失败导致全量中断
处理 CSV、JSON 数组或数据库查询结果时,某一行数值字段异常不应让整个任务崩溃。关键是把「解析」和「后续处理」解耦。
立即学习“Java免费学习笔记(深入)”;
- 用
Stream+filter(Optional::isPresent)过滤掉无效项,再map(Optional::get) - 记录失败条目时,保留原始上下文(如行号、字段名),例如:
log.warn("Failed to parse 'age' in row 42: '{}'", rawValue) - 避免在 for 循环里 try-catch 后 continue——这会让错误静默累积,后期难定位源头
ListvalidIds = Arrays.stream(rawIds) .map(YourUtil::safeParseInt) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList());
替代方案:用 Apache Commons Lang 的 NumberUtils
如果项目已引入 commons-lang3,NumberUtils 提供更简洁的工具方法,且行为比原生 API 更鲁棒。
-
NumberUtils.toInt("abc", -1)直接返回默认值,但注意:它对null和空字符串也返回默认值,和parseInt行为不一致 -
NumberUtils.createInteger("123")返回Integer对象(可为 null),比parseInt多一层空安全 - 不要依赖
NumberUtils.isCreatable()做预校验——它内部仍会触发一次解析,性能差且逻辑冗余
真正关键的不是选哪个工具,而是统一团队对「解析失败」的响应策略:是拒绝输入、降级处理,还是告警后跳过?这个决策点比代码写法更重要。










