1. Java Scanner基础用法详解
Scanner是Java中一个非常实用的工具类,位于java.util包中,主要用于解析基本类型和字符串的简单文本扫描器。它能够将输入分解为标记,然后使用不同的next方法将标记转换为不同类型的值。
1.1 Scanner的基本工作原理
Scanner类的工作原理可以理解为"输入流的解析器"。它接收一个输入源(可以是文件、字符串或系统输入流),然后按照指定的分隔符模式(默认是空白字符)将输入分解为标记。每个next方法都会尝试将下一个标记转换为指定的数据类型。
重要提示:Scanner不是线程安全的,如果多个线程同时使用一个Scanner实例,必须进行外部同步。
1.2 创建Scanner对象
创建Scanner对象的基本语法如下:
java复制Scanner scanner = new Scanner(System.in); // 从标准输入读取
也可以从其他输入源创建Scanner:
java复制Scanner fileScanner = new Scanner(new File("input.txt")); // 从文件读取
Scanner stringScanner = new Scanner("This is a string"); // 从字符串读取
1.3 常用方法解析
Scanner类提供了多种方法来读取不同类型的输入:
next(): 读取下一个标记(以空白字符分隔)nextLine(): 读取下一行文本nextInt(): 读取下一个整数nextDouble(): 读取下一个双精度浮点数hasNext(): 检查是否还有下一个标记hasNextLine(): 检查是否还有下一行hasNextInt(): 检查下一个标记是否可以解释为整数hasNextDouble(): 检查下一个标记是否可以解释为双精度浮点数
2. Scanner的实用示例
2.1 基本输入输出示例
下面是一个简单的Scanner使用示例,演示如何从控制台读取用户输入:
java复制import java.util.Scanner;
public class BasicScannerExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您的姓名:");
String name = scanner.nextLine();
System.out.println("您好," + name + "!");
scanner.close();
}
}
这个程序会提示用户输入姓名,然后输出问候语。注意我们使用了nextLine()方法来读取整行输入。
2.2 数值计算示例
Scanner也可以用于读取数值并进行计算,如计算多个数的和与平均值:
java复制import java.util.Scanner;
public class NumberCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double sum = 0;
int count = 0;
System.out.println("请输入数字(输入非数字结束):");
while (scanner.hasNextDouble()) {
double number = scanner.nextDouble();
count++;
sum += number;
System.out.println(count + "个数的和为:" + sum);
System.out.println(count + "个数的平均数为:" + (sum/count));
}
scanner.close();
}
}
这个程序会持续读取用户输入的数字,直到输入非数字为止,并实时计算和显示当前的和与平均值。
3. Scanner使用中的注意事项
3.1 next()与nextLine()的区别
next()和nextLine()是Scanner类中最容易混淆的两个方法:
next(): 读取输入直到遇到空白字符(空格、制表符、换行符等),返回读取的字符串(不包括空白字符)nextLine(): 读取输入直到遇到换行符,返回读取的字符串(不包括换行符)
常见问题场景:
java复制Scanner scanner = new Scanner(System.in);
System.out.print("请输入年龄:");
int age = scanner.nextInt();
System.out.print("请输入姓名:");
String name = scanner.nextLine(); // 这里会直接跳过输入
这是因为nextInt()只读取了数字,而没有读取后面的换行符。当调用nextLine()时,它会读取之前留下的换行符,导致看起来像是跳过了输入。
解决方案:
java复制Scanner scanner = new Scanner(System.in);
System.out.print("请输入年龄:");
int age = scanner.nextInt();
scanner.nextLine(); // 消耗掉换行符
System.out.print("请输入姓名:");
String name = scanner.nextLine();
3.2 资源管理与关闭
Scanner对象在使用完毕后应该关闭,以释放相关资源:
java复制Scanner scanner = new Scanner(System.in);
// 使用scanner...
scanner.close();
重要提示:一旦关闭Scanner,就不能再使用它。尝试在关闭后使用Scanner会抛出IllegalStateException。
3.3 输入验证
在实际应用中,应该总是验证用户的输入:
java复制Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个整数:");
while (!scanner.hasNextInt()) {
System.out.println("输入无效,请重新输入一个整数:");
scanner.next(); // 消耗掉无效输入
}
int number = scanner.nextInt();
System.out.println("您输入的整数是:" + number);
4. 高级Scanner技巧
4.1 使用分隔符
Scanner默认使用空白字符作为分隔符,但我们可以自定义分隔符:
java复制String input = "apple,orange,banana";
Scanner scanner = new Scanner(input);
scanner.useDelimiter(","); // 设置逗号为分隔符
while (scanner.hasNext()) {
System.out.println(scanner.next());
}
scanner.close();
输出:
code复制apple
orange
banana
4.2 区域设置
Scanner可以根据不同的区域设置解析数字:
java复制String input = "123,45";
Scanner scanner = new Scanner(input);
scanner.useLocale(Locale.FRENCH); // 在法语区域设置中,逗号是小数点分隔符
double number = scanner.nextDouble();
System.out.println(number); // 输出123.45
scanner.close();
4.3 正则表达式匹配
Scanner支持使用正则表达式查找特定模式的输入:
java复制String input = "1 fish 2 fish red fish blue fish";
Scanner scanner = new Scanner(input);
// 查找所有以"fish"结尾的单词
while (scanner.hasNext("\\w+fish")) {
System.out.println(scanner.next("\\w+fish"));
}
scanner.close();
输出:
code复制fish
fish
fish
fish
5. 常见问题与解决方案
5.1 Scanner输入阻塞问题
当使用System.in作为输入源时,Scanner会阻塞程序执行,直到用户输入内容。这在某些情况下可能导致程序看起来像是"卡住"了。
解决方案:
- 对于需要超时控制的场景,可以考虑使用
java.nio包中的非阻塞I/O - 或者使用单独的线程来处理输入
5.2 输入不匹配异常
当尝试使用nextInt()等方法读取输入,但输入内容不匹配预期类型时,会抛出InputMismatchException。
解决方案:
- 总是先使用
hasNext...()方法检查输入是否匹配预期类型 - 捕获并处理
InputMismatchException
java复制Scanner scanner = new Scanner(System.in);
try {
System.out.print("请输入一个整数:");
int number = scanner.nextInt();
System.out.println("您输入的是:" + number);
} catch (InputMismatchException e) {
System.out.println("输入的不是有效的整数!");
scanner.next(); // 消耗掉无效输入
}
5.3 多Scanner对象冲突
在同一程序中创建多个Scanner对象读取System.in可能会导致意外行为,因为输入流是共享的。
解决方案:
- 尽量只创建一个Scanner对象来读取
System.in - 如果需要多个Scanner,确保它们不会同时尝试读取输入
6. 性能优化建议
6.1 缓冲区的使用
对于大量输入,Scanner可能不是最高效的选择。考虑使用BufferedReader:
java复制BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line = reader.readLine(); // 读取一行
6.2 避免不必要的对象创建
不要在循环中重复创建Scanner对象:
java复制// 错误做法
while (condition) {
Scanner scanner = new Scanner(System.in);
// ...
scanner.close();
}
// 正确做法
Scanner scanner = new Scanner(System.in);
while (condition) {
// ...
}
scanner.close();
6.3 选择合适的读取方法
根据输入数据的特性选择最合适的读取方法:
- 对于行式输入,使用
nextLine() - 对于标记化输入,使用
next() - 对于特定类型的数据,使用对应的
next...()方法
7. 实际应用案例
7.1 简单的命令行计算器
java复制import java.util.Scanner;
public class SimpleCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("简单计算器");
System.out.println("1. 加法");
System.out.println("2. 减法");
System.out.println("3. 乘法");
System.out.println("4. 除法");
System.out.print("请选择操作(1-4): ");
int choice = scanner.nextInt();
System.out.print("请输入第一个数字: ");
double num1 = scanner.nextDouble();
System.out.print("请输入第二个数字: ");
double num2 = scanner.nextDouble();
double result = 0;
switch (choice) {
case 1: result = num1 + num2; break;
case 2: result = num1 - num2; break;
case 3: result = num1 * num2; break;
case 4: result = num1 / num2; break;
default: System.out.println("无效选择");
}
System.out.println("结果是: " + result);
scanner.close();
}
}
7.2 学生成绩录入系统
java复制import java.util.Scanner;
public class GradeSystem {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int studentCount = 0;
double totalScore = 0;
System.out.println("学生成绩录入系统");
System.out.println("输入'quit'结束录入");
while (true) {
System.out.print("请输入学生姓名: ");
String name = scanner.nextLine();
if (name.equalsIgnoreCase("quit")) {
break;
}
System.out.print("请输入" + name + "的成绩: ");
while (!scanner.hasNextDouble()) {
System.out.println("请输入有效的数字成绩!");
scanner.next(); // 消耗无效输入
System.out.print("请输入" + name + "的成绩: ");
}
double score = scanner.nextDouble();
scanner.nextLine(); // 消耗换行符
studentCount++;
totalScore += score;
System.out.println(name + "的成绩已录入: " + score);
}
if (studentCount > 0) {
System.out.println("共录入" + studentCount + "名学生");
System.out.println("平均成绩: " + (totalScore / studentCount));
} else {
System.out.println("没有录入任何学生成绩");
}
scanner.close();
}
}
7.3 文件内容分析工具
java复制import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class FileAnalyzer {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入要分析的文件路径: ");
String filePath = scanner.nextLine();
try {
File file = new File(filePath);
Scanner fileScanner = new Scanner(file);
int wordCount = 0;
int lineCount = 0;
while (fileScanner.hasNextLine()) {
String line = fileScanner.nextLine();
lineCount++;
Scanner lineScanner = new Scanner(line);
while (lineScanner.hasNext()) {
lineScanner.next();
wordCount++;
}
lineScanner.close();
}
System.out.println("文件分析结果:");
System.out.println("行数: " + lineCount);
System.out.println("单词数: " + wordCount);
fileScanner.close();
} catch (FileNotFoundException e) {
System.out.println("文件未找到: " + filePath);
}
scanner.close();
}
}
在实际开发中,Scanner是一个非常实用的工具类,掌握它的各种用法可以大大提高处理用户输入和文本解析的效率。通过合理使用Scanner的各种方法,并注意处理可能出现的异常情况,可以构建出健壮且用户友好的命令行应用程序。