Scanner类

背景与动机#

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():读取并解析下一个 int
  • nextDouble():读取并解析下一个 double
  • hasNext():判断是否还有下一个标记
  • hasNextInt():判断下一个标记能不能按 int 解析
  • hasNext(String pattern):判断下一个标记是否匹配指定正则

img
img

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() 失效了,而是:

  1. nextInt() 只把数字本身读走了。
  2. 你按下回车时留下的换行符还在输入缓冲区里。
  3. 后面的 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() 判断,混用时特别注意换行残留问题。

文章目录

文章目录