Scanner 输入阻塞或乱码主因是底层输入流编码不统一及换行符残留;需统一JVM与终端UTF-8编码,nextXxx()后手动调用nextLine()清缓存,或统一用nextLine()解析,必要时改用BufferedReader+InputStreamReader指定编码。

Scanner 在读取输入时出现阻塞或乱码,通常不是 Scanner 本身的问题,而是底层输入流(如 System.in)的缓冲机制和字符编码未与终端/控制台环境对齐所致。关键在于统一编码、避免残留换行符干扰、以及理解阻塞发生的实际场景。
确认并统一 JVM 与终端的字符编码
Java 默认使用平台编码读取 System.in,但 IDE(如 IntelliJ)、Windows CMD、PowerShell、Linux 终端或 Git Bash 的默认编码可能不同(如 GBK、UTF-8、ISO-8859-1),导致中文输入显示为乱码。
- 运行前显式指定 JVM 编码:启动时加参数
-Dfile.encoding=UTF-8(推荐所有环境统一用 UTF-8) - 在 IDE 中设置:IntelliJ → Settings → Editor → File Encodings → Project Encoding 和 Default encoding for properties files 改为 UTF-8;同时在 Run Configuration → VM options 中添加上述参数
- Windows CMD 下临时切换:执行
chcp 65001(启用 UTF-8),再运行程序
避免 nextXxx() 后 nextLine() 的“跳过”假象
这是最常见“阻塞错觉”:调用 next(), nextInt(), nextDouble() 等方法不会消费其后的换行符(\n),紧接着调用 nextLine() 就会立即返回空字符串——看似“没输入就继续了”,实则是读到了残留换行符。
- 解决方式:在每个
nextXxx()后手动加一次scanner.nextLine()清除缓冲区 - 更稳妥做法:统一用
nextLine()读取整行,再自行解析(如Integer.parseInt(line)),避免混合使用 - 示例:错误写法:
int n = s.nextInt(); String s1 = s.nextLine();→ s1 为空;正确写法:int n = Integer.parseInt(s.nextLine()); String s1 = s.nextLine();
识别真正阻塞:等待用户输入 vs 缓冲区未刷新
Scanner 阻塞本质是 System.in.read() 在等待字节到达。若程序卡住不动,需排查:
- 是否在 IDE 控制台中粘贴输入但未按回车?Scanner 的
nextLine()必须遇到换行才返回 - 是否误将输入重定向(如
java Main < input.txt),而文件末尾缺少换行符?部分系统下会导致nextLine()持续等待 EOF - 是否在管道或子进程中使用 Scanner?确保上游进程已正确关闭输出流,否则
System.in不会收到 EOF
替代方案:用 BufferedReader + InputStreamReader 更可控
当 Scanner 行为难以调试时,可改用更底层、编码明确的组合:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));- 它不自动跳过空白、不缓存 token,行为更直观;且编码直接指定,规避默认编码歧义
- 读取仍用
reader.readLine(),返回 null 表示 EOF,无隐式换行符残留问题

















