为什么IntelliJ调试模式下程序会抛出NoSuchElementException异常
异常仅在调试模式出现的原因
- 代码本身存在逻辑漏洞:你直接调用
Scanner.nextLine(),没有预先通过hasNextLine()判断是否存在可用输入,一旦System.in输入流到达EOF(被关闭),该方法必然抛出java.util.NoSuchElementException。 - 普通运行模式无报错的原因:IntelliJ普通运行模式下点击终止按钮时,IDE会直接向Java进程发送终止信号,进程会被立刻杀死,没有机会执行异常抛出和栈信息打印的逻辑,因此看不到报错,不代表代码运行正常。
- 调试模式出现报错的原因:IntelliJ调试模式通过JDWP协议和目标VM交互,你点击终止按钮时,IDE会先关闭目标进程的标准输入流
System.in,再断开调试器连接,此时阻塞在nextLine()的调用会检测到输入流已到EOF,触发异常抛出,栈信息会在进程完全退出前打印到控制台,因此你能看到报错。 - 环境适配性问题:你使用的IntelliJ IDEA 2021.1.3版本在macOS Big Sur系统下对调试进程的输入流处理有特定逻辑,进一步放大了两种运行模式的终止行为差异。
规避方案
- 方案1:调用
nextLine()前先判断输入是否存在,从根源避免异常触发,Groovy修正代码如下:
class Main { static void main(String[] args) { def scanner = new Scanner(System.in) if (scanner.hasNextLine()) { scanner.nextLine() } } }
Java版本修正逻辑完全一致,先调用scanner.hasNextLine()判断再执行nextLine()即可。
- 方案2:如果业务逻辑需要持续阻塞等待用户输入,不需要处理输入流被关闭的场景,可以直接捕获对应异常做静默处理:
class Main { static void main(String[] args) { try { new Scanner(System.in).nextLine() } catch (java.util.NoSuchElementException ignored) { // 输入流关闭时直接退出进程即可 } } }
- 方案3:升级IntelliJ IDEA到2022.1及以上版本,该版本对调试模式下的进程终止逻辑做了优化,和普通运行模式的终止行为保持一致,也可以避免该异常打印。
内容的提问来源于stack exchange,提问作者Koray Tugay
相关产品推荐
相关产品推荐

