背景与动机
Scanner 是 Java 里最常见的输入解析工具之一,位于 java.util 包中。初学阶段最常见的用法是读取控制台输入,但它并不只服务于键盘输入,也可以从字符串、文件、输入流中按“标记”或“行”来解析数据。
学习 Scanner 时,真正容易踩坑的地方不是“怎么 new 一个对象”,而是:
next()和nextLine()到底读到哪里为止nextInt()、nextDouble()这类方法和nextLine()混用时为什么会读到空串- 什么时候该配合
hasNextXxx()先判断,再读取
核心原理拆解
1. 基本创建方式
控制台输入最常见的写法如下:
import java.util.Scanner;
public class ScannerDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); }}这里的 System.in 表示标准输入流,也就是终端里输入的内容。
2. Scanner 在读什么
可以先把 Scanner 理解成一个“带规则的文本读取器”。
next()按空白符分隔读取下一个标记nextInt()、nextDouble()等方法会尝试把下一个标记解析成指定类型nextLine()按整行读取,直到遇到换行hasNext()、hasNextInt()、hasNext(String pattern)用来先判断,再决定是否读取
常用方法可以先记住这几个:
next():读取下一个字符串标记,遇到空格、Tab、换行就结束nextLine():读取当前行剩余的全部内容nextInt():读取并解析下一个intnextDouble():读取并解析下一个doublehasNext():判断是否还有下一个标记hasNextInt():判断下一个标记能不能按int解析hasNext(String pattern):判断下一个标记是否匹配指定正则

3. next() 只读取一个标记
next() 的结束条件不是“读完整行”,而是“读到空白分隔符”。所以它非常适合读取单个单词、单个数字、单个命令参数,但不适合直接读取带空格的一整句文本。
import java.util.Scanner;
public class NextDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入一个字符串:"); String str = scanner.next(); System.out.println("您输入的字符串为:" + str); }}输入和输出效果:
请输入一个字符串:bug您输入的字符串为:bug如果输入的是:
adad dada dsada2最终输出会是:
您输入的字符串为:adad因为 next() 只读取空格前面的部分。
4. nextLine() 读取整行内容
如果你的目标是读取一句完整的话、一个带空格的地址,或者一整行配置文本,通常应当使用 nextLine()。
import java.util.Scanner;
public class NextLineDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入一个字符串:"); String str = scanner.nextLine(); System.out.println("您输入的字符串为:" + str); }}输入:
abcd 123 hhhh输出:
您输入的字符串为:abcd 123 hhhh它会把当前行里剩余的所有字符一起读走,包括空格。
5. next() 和 nextLine() 的核心区别
最实用的记法是:
next()按“词”读,遇到空白符就停nextLine()按“行”读,遇到换行才停
对比起来看更清楚:
| 方法 | 读取范围 | 是否能读取空格 | 常见场景 |
|---|---|---|---|
next() | 下一个标记 | 否 | 单词、单个参数、单个数字字符串 |
nextLine() | 当前行剩余内容 | 是 | 一整句话、一整行文本 |
6. 为什么 nextInt() 后面接 nextLine() 会出问题
这是 Scanner 最常见的坑之一。
import java.util.Scanner;
public class ScannerTrapDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in);
System.out.println("请输入年龄:"); int age = scanner.nextInt();
System.out.println("请输入姓名:"); String name = scanner.nextLine();
System.out.println(age); System.out.println(name); }}很多人会发现 name 直接变成空字符串。原因不是 nextLine() 失效了,而是:
nextInt()只把数字本身读走了。- 你按下回车时留下的换行符还在输入缓冲区里。
- 后面的
nextLine()读到这个换行符后立刻结束,于是返回空串。
修复方式一般是在中间额外补一次 nextLine(),把上一行残留的换行消费掉:
import java.util.Scanner;
public class ScannerFixDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in);
System.out.println("请输入年龄:"); int age = scanner.nextInt(); scanner.nextLine();
System.out.println("请输入姓名:"); String name = scanner.nextLine();
System.out.println("age = " + age); System.out.println("name = " + name); }}最小可运行代码示例
下面这个例子把 hasNext(String pattern) 和 next() 放在一起,演示如何校验用户输入的日期格式:
import java.util.Scanner;
public class ScannerPatternDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入一个 yyyy-MM-dd 格式的日期:");
if (scanner.hasNext("^\\d{4}-\\d{2}-\\d{2}$")) { System.out.println("输入的日期为:" + scanner.next()); } else { System.out.println("输入的日期格式错误!"); } }}示例输出:
请输入一个 yyyy-MM-dd 格式的日期:2022-06-29输入的日期为:2022-06-29这里要注意,正则只能校验“格式像不像日期”,并不能保证这个日期一定真实有效。比如 2022-99-99 仍然可能通过格式校验。要做严格日期校验,通常还要配合 LocalDate.parse() 进一步验证。
常见陷阱与错误示例
1. 以为 next() 能读取一整句话
如果输入里包含空格,next() 只会拿到第一个标记。要读取完整一行,应改用 nextLine()。
2. nextInt() 和 nextLine() 混用时忘记处理换行
这是最常见的问题。数值读取方法不会自动把“这一行已经结束”的语义一起处理掉,所以经常需要手动补一个 nextLine()。
3. 不做判断就直接调用 nextInt()
如果用户输入的不是整数,程序会抛出输入不匹配异常。更稳妥的方式是先用 hasNextInt() 判断,再决定是否读取。
if (scanner.hasNextInt()) { int n = scanner.nextInt();} else { System.out.println("请输入合法整数");}4. 随手关闭 System.in 对应的 Scanner
如果 Scanner 是基于 System.in 创建的,调用 scanner.close() 会把底层输入流一起关掉。对于简单的单次命令行程序问题不大,但在一些需要继续读取标准输入的场景里,要注意这个副作用。
面试高频问题
1. next() 和 nextLine() 有什么区别
next() 按空白符读取下一个标记,nextLine() 按整行读取直到换行。
2. 为什么 nextInt() 后再调用 nextLine() 容易读到空串
因为 nextInt() 只读取数字,不会消耗回车留下的换行符,后面的 nextLine() 会直接把这个换行读走。
3. hasNextXxx() 的作用是什么
它的作用是先判断下一个输入是否满足条件,再决定是否读取,避免直接调用 nextXxx() 时抛异常。
4. hasNext(String pattern) 能不能校验合法日期
它更适合做“格式匹配”,不能完全替代真正的业务校验。像 yyyy-MM-dd 这种格式可以先用正则筛一遍,再用日期 API 做严格验证。
一句话总结
Scanner 的核心不是“读取输入”这么简单,而是“按不同规则解析输入”:读单个标记用 next(),读整行用 nextLine(),读数值前最好先配合 hasNextXxx() 判断,混用时特别注意换行残留问题。