NumberFormatException是parseXXX方法解析非数字字符串时抛出的unchecked异常,需用try-catch处理,推荐用NumberUtils或自封装safeParseInt,并前置校验null、空串及Unicode兼容性。

NumberFormatException 本质是 parseXXX 遇到非数字字符串
它不是运行时环境问题,也不是 JVM 配置错误,而是 Integer.parseInt、Long.parseLong 这类方法在碰到无法解析的字符串(比如 "123abc"、"null"、""、" 456 ")时,直接抛出的 unchecked 异常。不捕获就崩,捕获后没处理好逻辑照样出错。
常见错误现象:NumberFormatException: For input string: "null" 或 "For input string: "" —— 这说明你传进去的压根不是“看起来像数字”的字符串,而是空值或空白。
- 先检查输入是否为
null或空字符串:str == null || str.trim().isEmpty() - 再检查是否只含数字字符(注意:负号、小数点、科学计数法都不行,除非用
Double.parseDouble) -
parseInt不接受前导空格,trim()必须显式调用
用 valueOf + try-catch 比直接 parse 更安全
Integer.valueOf 和 Integer.parseInt 底层都走同一套解析逻辑,区别在于前者返回 Integer 包装类(可能触发缓存),后者返回基本类型 int。但关键不是选哪个函数,而是**必须配合 try-catch 使用**——没有例外。
别信“我数据源很干净”,线上总有意外:前端传参被截断、日志补全字段填了 "N/A"、数据库默认值是 "-"……
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
try {
int num = Integer.parseInt(str.trim());
// 处理合法数字
} catch (NumberFormatException e) {
// 记录日志,返回默认值,或抛业务异常
log.warn("Invalid number format: {}", str);
return -1; // 或 throw new BusinessException("参数非法");
}
- 不要用
str.matches("\d+")做预校验:它不支持负数,且正则比 try-catch 开销更大 - 避免在循环里反复 try-catch:如果批量解析,可先过滤掉明显非法字符串(如含字母、长度超限)再进 parse
-
Long.parseLong同理,但要注意溢出:"99999999999999999999"会抛异常,不是截断
替代方案:Apache Commons Lang 的 NumberUtils
如果你项目已引入 commons-lang3,NumberUtils.toInt(str)、NumberUtils.createInteger(str) 是更省心的选择——它们内部做了 null 和空串保护,失败时返回默认值或 null,不用手写 try-catch。
例如:NumberUtils.toInt("abc", 0) 返回 0;NumberUtils.createInteger(" 789 ") 返回 789(自动 trim);NumberUtils.toInt(null, -1) 返回 -1。
- 不依赖第三方?那就自己封装一个:
safeParseInt(String s, int defaultValue),里面做 trim + try-catch - 注意
NumberUtils.toInt("12.3")返回0(不是四舍五入),它只认整数格式 - 性能差异极小,别为这点开销拒绝可读性提升
边界场景:Unicode 数字、全角字符、千分位符号
parseInt 只认 ASCII 数字 '0'-'9'、可选的开头 '-' 或 '+'。遇到全角数字 "123"、阿拉伯数字 Unicode 字符、中文逗号 "1,234",一律报错。
这类问题通常出现在国际化输入或 OCR 结果中,不能靠加 try-catch 解决,得前置清洗:
- 用
str.replaceAll("[^\d-+]", "")粗暴去除非数字字符(慎用,会干掉负号位置) - 更稳妥的是用
Normalizer.normalize(str, Normalizer.Form.NFD)转换 Unicode 兼容形式,再替换全角数字 - 千分位符号建议由前端/协议层约定不传,后端不负责格式识别
真正难搞的不是“怎么转”,而是“谁该负责清理输入”——这个责任一旦模糊,NumberFormatException 就会反复出现在意想不到的地方。

















