Java Scanner 类精讲:控制台交互

Java Scanner 类精讲:控制台交互
1.1 什么是 ScannerScanner 是 Java 5.0 新增的基于字符流的解析工具类位于java.util包下。它的核心设计目标是简化用户交互和数据读取场景的开发工作把底层的字节流InputStream自动转换为字符流支持多种字符集编码基于自定义分隔符默认空格、换行符将输入流切分成独立的令牌将字符串类型的令牌自动转换成开发者需要的基本数据类型int、long、double、boolean 等和字符串类型内置正则校验逻辑。1.2 Scanner 的核心应用场景Scanner 不是用来处理高性能 IO 的工具类它的核心适配场景集中在人机交互和简单数据读取这也是我们今天重点覆盖的范围场景分类具体用途工业级使用限制控制台用户交互读取用户输入的的用户名、密码、年龄、订单号、确认指令y/n不推荐在高并发场景的后端服务中使用仅用于控制台程序或内部工具的人机交互简单文件读取读取配置文件、小型日志文件、批量导入的文本数据如 csv、txt超过 100MB 的大文件必须搭配缓冲区优化或改用BufferedReader网络请求流解析读取简单的 HTTP 响应、Socket 输入流按分隔符拆分数据复杂网络协议或高并发场景必须改用 Netty 等 NIO 框架字符串分词处理拆分复杂格式的字符串如逗号分隔的 ID 列表、JSON 片段提取复杂结构化数据推荐使用 Jackson、Gson 等专业序列化工具1.3 Scanner vs BufferedReader核心差异很多开发者会混淆这两个读取工具类二者在设计目标、底层逻辑、性能表现上完全不同选型错误是线上故障的根源之一对比维度ScannerBufferedReader核心设计目标简化数据解析将字节流转换为字符流自动拆分令牌、转换数据类型提升 IO 读取性能为底层字符流提供 8KB 的缓冲能力减少 IO 交互次数处理流类型字节流InputStream、字符流Readable字符流Reader可通过InputStreamReader适配字节流数据读取方式基于自定义分隔符将流拆分为令牌再进行类型转换按字符数组、行、固定长度读取流无内置令牌拆分逻辑数据类型转换内置支持基本数据类型、字符串转换内置正则校验仅支持读取字符或字符串需要手动进行类型转换读取效率慢final 类无锁设计内置解析逻辑单次读取涉及多次 IO 操作快abstract 类采用装饰器模式单次读取涉及少量 IO 操作线程安全性非线程安全多线程场景下必须做同步处理非线程安全多线程场景下必须做同步处理工业级选型场景控制台交互、简单文件解析、低并发场景的数据流处理大文件读取、高并发场景的数据流处理、高性能 IO 场景【博主经验批注】我在生产环境见过用 Scanner 读取 10GB 级别的日志文件导致整个服务的 CPU 占用率飙升至 100%最终触发 OOM。核心原因就是 Scanner 的设计目标是简化解析而不是高性能读取。2.1 基本使用步骤Scanner 的工作逻辑非常固定所有场景下的编码步骤都是标准的 4 步模板// 1. 引入Scanner类必须在文件顶部导入 import java.util.Scanner; public class ConsoleInteractionDemo { #x20; public static void main(String\[] args) { #x20; // 2. 构造Scanner对象传入底层字节流这里用System.in读取控制台输入 #x20; Scanner scanner new Scanner(System.in); #x20; #x20; #x20; // 3. 调用nextXxx()方法读取并解析用户输入转换成目标类型 #x20; System.out.print(请输入您的用户名); #x20; String username scanner.nextLine(); // 读取一行字符串包含空格直到遇到换行符 #x20; #x20; #x20; System.out.print(请输入您的年龄); #x20; int age scanner.nextInt(); // 读取一个整数自动跳过分隔符做数字格式校验 #x20; #x20; #x20; System.out.print(请输入您的身高单位米); #x20; double height scanner.nextDouble(); // 读取一个浮点数自动做格式校验 #x20; #x20; #x20; System.out.print(请输入您的确认指令y/n); #x20; String confirm scanner.next(); // 读取一个令牌默认以空格、换行符为分隔符 #x20; #x20; #x20; // 4. 关闭Scanner流释放底层IO资源避免资源泄漏 #x20; scanner.close(); #x20; } }2.2 核心 API 用法差异解析这是初学者最容易搞混的点不同的读取方法对分隔符的处理逻辑完全不同—— 理解这一点是后续规避经典坑的前提。方法名作用描述分隔符处理逻辑返回值适配场景nextLine()读取一整行输入包含空格直到遇到换行符会读取当前位置到换行符之间的所有字符会吃掉换行符本身将光标移动到换行符之后的下一个位置字符串不含末尾的换行符读取包含空格的用户名、地址、多行备注信息next()读取下一个有效令牌默认以空格、换行符、制表符为分隔符会自动跳过开头的所有分隔符然后读取直到下一个分隔符之前的所有字符不会吃掉末尾的分隔符光标停在分隔符之前字符串不含首尾的分隔符读取不包含空格的指令、订单号、手机号、验证码nextInt()/nextLong()/nextDouble()读取并解析下一个令牌转换成对应的基本数据类型内部调用next()读取字符串令牌再尝试转换为目标类型不会吃掉末尾的分隔符光标停在分隔符之前对应的基本数据类型读取年龄、金额、数量、分页参数等数字类输入nextBoolean()读取并解析下一个令牌转换为布尔类型内部调用next()读取字符串令牌再校验是否为true/false忽略大小写布尔类型读取确认状态、开关标记、布尔类指令hasNext()/hasNextXxx()校验输入流中是否还有下一个令牌是否匹配指定的正则表达式会阻塞等待用户输入直到检测到分隔符或流结束标记不会移动光标布尔类型有下一个有效令牌则返回true循环读取输入、做输入合法性校验避免异常2.3 正确关闭流资源Scanner 实现了Closeable接口必须调用close()方法关闭流释放底层 IO 资源否则会导致资源泄漏长期运行会导致文件句柄或 socket 连接耗尽。工业级场景下必须使用try-with-resources语法自动关闭流资源保证异常发生时也能正常释放资源不用手动调用close()方法。代码示例如下public class TryWithResourcesDemo { #x20; public static void main(String\[] args) { #x20; // try-with-resources语法在try关键字后的括号中声明Scanner对象try代码块执行完后会自动关闭 #x20; try (Scanner scanner new Scanner(System.in)) { #x20; System.out.print(请输入您的用户名); #x20; String username scanner.nextLine(); #x20; System.out.println(您输入的用户名是 username); #x20; } // 无论是否发生异常这里都会自动调用scanner.close()方法释放IO资源 #x20; } }