Scanner.hasNextInt()并非安全的nextInt()预检,它仅判断下一个token是否为十进制整数且不消费输入;若其间有nextLine()等操作干扰位置,或nextInt()后残留换行符,仍会抛InputMismatchException;健壮做法是try-catch捕获异常并用nextLine()清理非法token。

Scanner.hasNextInt() 不是“安全的 nextInt()”
它只检查下一个 token 是否能解析成 int,但不消费输入流;如果调用 nextInt() 前没调用 hasNextInt(),或检查后中间有其他操作干扰了 scanner 的位置,依然会抛 InputMismatchException。
常见错误现象:hasNextInt() 返回 true,但紧接着 nextInt() 还是报错——通常是因为之前调用了 nextLine() 留下的换行符,导致 scanner 实际停在空行上,hasNextInt() 检查的是下一行(而你没意识到)。
- 必须确保
hasNextInt()和nextInt()之间没有其他nextXxx()或nextLine()干扰 scanner 的 token 位置 - 如果前面用过
nextLine()(比如读字符串),之后要读 int,得先确认当前 token 是整数,或手动跳过空白:用scanner.skip("\s*") -
hasNextInt()只认十进制整数,不识别带前导零的八进制(如"012")或十六进制(如"0xFF"),这些会返回false
用 try-catch + nextLine() 清理输入流才是真健壮
依赖 hasNextInt() 做预检,在交互式输入中极易失效。真正可控的做法是:直接尝试 nextInt(),捕获异常,再用 nextLine() 吃掉非法 token 和残留换行符。
使用场景:命令行工具、算法题输入、简单控制台交互——即用户可能乱输、粘贴多行、或中途 Ctrl+C 中断的环境。
立即学习“Java免费学习笔记(深入)”;
- 不要写
if (scanner.hasNextInt()) { scanner.nextInt(); },这掩盖了 scanner 内部状态混乱的风险 - 写法应为:
try { int x = scanner.nextInt(); } catch (InputMismatchException e) { scanner.nextLine(); // 吃掉非法 token System.out.println("请输入一个整数"); } - 注意:
nextLine()必须在 catch 里调用,且只能调一次;多次调用可能跳过下一行有效输入 - 如果连续读多个 int,每次失败后都必须清理,否则后续
nextInt()仍卡在同一个坏 token 上
nextInt() 的换行符残留问题比想象中更顽固
nextInt() 只读数字,不读后面的换行符(
),所以下一个 nextLine() 会立刻返回空字符串——这不是 bug,是设计行为。但很多人误以为是 hasNextInt() 没用好,其实根源在这。
性能影响:额外一次 nextLine() 几乎无开销;但若漏处理,会导致后续所有 nextLine() 读取错位,逻辑雪崩。
- 只要你在
nextInt()后紧接着需要nextLine()(比如先读数量,再读一行字符串),就必须补一句scanner.nextLine() - 不能用
hasNextLine()替代——它只是看有没有下一行,不解决换行符滞留问题 - 如果整个流程只读 int,不碰
nextLine(),那换行符残留不影响逻辑,但调试时容易误判输入位置
替代方案:用 next().matches("\d+") + Integer.parseInt 更可控?
可以,但没必要过度优化。用 next() 读 token、正则校验、再转整数,确实绕开了 Scanner 的状态陷阱,但引入了新坑:无法区分负数("-123")、长整数溢出(Integer.parseInt() 抛 NumberFormatException)、以及空格分隔逻辑需自行维护。
兼容性影响:正则方式在 Android 低版本或嵌入式 JRE 中可能受限;而 Scanner 是标准库,行为稳定。
- 如果明确只要非负整数,且输入格式严格(空格分隔、无负号),
next().matches("\d+")可用,但记得捕获NumberFormatException - 涉及负数?改用
next().matches("-?\d+"),但要注意"-0"合法,而"- 123"(带空格)不匹配——Scanner 默认跳过前导空白,正则方式得自己处理 - 真正复杂输入建议换
BufferedReader + String.split()或 Jackson/ Gson 解析 JSON,别硬扛 Scanner
Scanner 的状态机很轻量,但也很脆弱。最常被忽略的不是“怎么读对”,而是“读错之后,输入流指针到底停在哪”。每次异常后不清理,等于把问题留给下一次调用。










