Java Scanner 类精讲:控制台交互

1.1 什么是 Scanner?

Scanner 是 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:核心差异

很多开发者会混淆这两个读取工具类,二者在设计目标、底层逻辑、性能表现上完全不同,选型错误是线上故障的根源之一:

对比维度 Scanner BufferedReader
核心设计目标 简化数据解析:将字节流转换为字符流,自动拆分令牌、转换数据类型 提升 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 {

    public static void main(String\[] args) {

        // 2. 构造Scanner对象,传入底层字节流,这里用System.in读取控制台输入

        Scanner scanner = new Scanner(System.in);

        

        // 3. 调用nextXxx()方法,读取并解析用户输入,转换成目标类型

        System.out.print("请输入您的用户名:");

        String username = scanner.nextLine(); // 读取一行字符串,包含空格,直到遇到换行符

        

        System.out.print("请输入您的年龄:");

        int age = scanner.nextInt(); // 读取一个整数,自动跳过分隔符,做数字格式校验

        

        System.out.print("请输入您的身高(单位:米):");

        double height = scanner.nextDouble(); // 读取一个浮点数,自动做格式校验

        

        System.out.print("请输入您的确认指令(y/n):");

        String confirm = scanner.next(); // 读取一个令牌,默认以空格、换行符为分隔符

        

        // 4. 关闭Scanner流,释放底层IO资源,避免资源泄漏

        scanner.close();

    }

}

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 {

    public static void main(String\[] args) {

        // try-with-resources语法:在try关键字后的括号中声明Scanner对象,try代码块执行完后会自动关闭

        try (Scanner scanner = new Scanner(System.in)) {

            System.out.print("请输入您的用户名:");

            String username = scanner.nextLine();

            System.out.println("您输入的用户名是:" + username);

        } // 无论是否发生异常,这里都会自动调用scanner.close()方法,释放IO资源

    }

}
相关推荐
chh5631 小时前
C++--string
java·开发语言·网络·c++·学习
Listen·Rain1 小时前
向量化详解
java·人工智能·spring·机器学习·ai
想你依然心痛1 小时前
AUTOSAR Classic Platform架构解析:BSW、RTE与ASW——分层、配置、代码生成
java·架构·实时互动
梦想的旅途21 小时前
企业微信外部群智能自动回复:基于RPA接口的关键词匹配方案
java·开发语言·数据库·机器人·自动化·企业微信
娇气的红酒1 小时前
关于.NET VS JavaEE平台争论的沉思录
java·java-ee·.net
折哥的程序人生 · 物流技术专研1 小时前
第3篇:手写一个饮品制作模板(附代码)
java·设计模式·行为型模式·模版方法模式·钩子方法·代码复用·编程实战
SamDeepThinking1 小时前
为什么很多人学了Java,还是没真正理解类和对象?
java·后端·面试
逝水无殇2 小时前
C# 多态性详解
开发语言·后端·c#
逝水无殇2 小时前
C# 继承(Inheritance)详解
开发语言·后端·c#