Java用Scanner为对象属性赋值时抛InvocationTargetException排查
Scanner 读取输入时抛出 InvocationTargetException 问题分析
根本原因
- 代码中
setPersonalId()方法的实现存在致命问题:它用try-with-resources语法创建了绑定System.in的Scanner实例try ( Scanner scanner2 = new Scanner(System.in); ) { - try-with-resources机制会在代码块执行完成后自动关闭持有的资源。由于Scanner是对
System.in全局输入流的包装类,关闭Scanner对象时,底层关联的System.in输入流会被一并彻底关闭。 - 等
setPersonalId()执行完毕回到SignPerson()方法,无论你后续创建多少个新的Scanner实例去调用nextLine()读取输入,都会因为底层System.in已经处于关闭状态抛出IO异常。 - 你看到的
InvocationTargetException只是一层包装壳:这个异常通常是反射调用场景下,JVM把目标方法内部抛出的原始异常包装后抛出的类型,本身不携带具体错误信息,如果你只盯着外层的异常类型搜索解决方案,自然找不到问题根因——真正的“输入流已关闭”的错误信息,藏在这个异常的cause节点里。 - 这也是为什么你换其他Scanner实例也会抛异常的原因:
System.in是JVM启动时初始化的全局单例输入流,只要被关闭过一次,后续所有绑定它的读取操作都会直接失败——哪怕你换成BufferedReader去读输入也一样报错,和换不换Scanner对象没有关系。
修复方案
- 全程序范围只维护一个绑定
System.in的Scanner实例,不要在局部方法里反复创建、关闭绑定系统输入流的Scanner:- 把Scanner实例提升为类级别的全局成员,整个注册流程共用同一个对象
- 删除
setPersonalId()里单独创建Scanner的逻辑,直接复用全局的Scanner实例读取pesel输入,同时移除try-with-resources的自动关闭逻辑,避免全局输入流被意外关闭 - 排查这类包装异常时,记得打印完整的异常调用链,顺着
InvocationTargetException往下找嵌套的原始异常,才能看到真正的报错原因
内容的提问来源于stack exchange,提问作者Jakub Kołacz
相关产品推荐
相关产品推荐

