NoSuchElementException死循环与PMD DD异常相关代码问题求助
问题根因
- 你代码里最核心的错误是在try-with-resources语法中创建Scanner实例:try-with-resources会在代码块执行结束后自动关闭资源,你关闭Scanner的同时会连带关闭底层的
System.in输入流。第一次循环结束后System.in就已经是关闭状态,后续循环再新建Scanner读取已经关闭的流,就会持续抛出NoSuchElementException,进入无限循环。 - 其次你提到的
nextLine()相关问题是第二个常见误区:scanner.nextInt()只会读取输入的数字部分,不会消费数字后面的换行符,缓冲区残留的换行符会被下一次nextLine()直接读取到空内容,导致逻辑异常。
修复方案
方案1:全局复用同一个Scanner实例,不要每次循环新建也不要随便关闭
你可以把Scanner定义为类成员变量,或者在方法外创建后传入,避免反复开闭System.in,同时处理掉nextInt残留的换行符:
public class Console { // 全局复用同一个Scanner,不要主动关闭 private final Scanner scanner = new Scanner(System.in); public int readInteger(String prompt) { Integer x = null; while(x == null) { try { System.out.print(prompt); x = scanner.nextInt(); // 消费掉数字后面残留的换行符,避免影响后续nextLine调用 scanner.nextLine(); } catch(InputMismatchException exc) { System.out.println("输入错误,请输入合法整数"); // 输入不匹配的时候也要把错误的整行输入消费掉,避免无限卡这里 scanner.nextLine(); } catch(NoSuchElementException exc) { System.out.println("输入流已关闭,无法读取内容"); // 流已关闭无需继续循环,直接抛出或者返回默认值即可,这里选择抛出终止逻辑 throw new RuntimeException("输入流已终止", exc); } } return x; } }
方案2:直接统一用nextLine读取整行再转成整数,彻底避免换行残留问题
如果你的场景后续要频繁混用读取整数和字符串,更稳妥的方式是所有输入都按行读取,再做类型转换:
public int readInteger(String prompt) { Integer x = null; while(x == null) { try { System.out.print(prompt); String input = scanner.nextLine(); x = Integer.parseInt(input); } catch(NumberFormatException exc) { System.out.println("输入错误,请输入合法整数"); } catch(NoSuchElementException exc) { System.out.println("输入流已关闭,无法读取内容"); throw new RuntimeException("输入流已终止", exc); } } return x; }
注意事项
- 不要在任何场景下关闭包装了
System.in的Scanner,一旦关闭System.in整个程序生命周期内都无法再重新打开读取输入。 - 所有异常分支都要记得消费掉当前缓冲区的无效内容,否则异常后缓冲区残留的内容会被下一次读取逻辑重复触发异常,导致无限循环。
内容的提问来源于stack exchange,提问作者nighty
相关产品推荐
相关产品推荐

