1. 概述

在本文中,我们将深入探讨 Java 中 BufferedReader、Console 和 Scanner 类之间的区别

如果你希望更深入地了解每一个类,建议参考我们之前的相关文章:Java ScannerJava 控制台输入输出BufferedReader

2. 用户输入处理能力

根据传入构造函数的底层流不同,BufferedReader 和 Scanner 都可以处理多种类型的输入源,例如字符串、文件、系统控制台(通常连接键盘)以及 Socket 输入流等。

Console 类则专门用于访问与当前 JVM 关联的字符型系统控制台(如果存在的话)。

来看一下 BufferedReader 的几种构造方式,支持多种输入来源:

BufferedReader br = new BufferedReader(
  new StringReader("Bufferedreader vs Console vs Scanner in Java"));
BufferedReader br = new BufferedReader(
  new FileReader("file.txt"));
BufferedReader br = new BufferedReader(
  new InputStreamReader(System.in))

Socket socket = new Socket(hostName, portNumber);
BufferedReader br =  new BufferedReader(
  new InputStreamReader(socket.getInputStream()));

Scanner 同样支持类似的输入源:

Scanner sc = new Scanner("Bufferedreader vs Console vs Scanner in Java")
Scanner sc = new Scanner(new File("file.txt"));
Scanner sc = new Scanner(System.in);

Socket socket = new Socket(hostName, portNumber);
Scanner sc =  new Scanner(socket.getInputStream());

而 Console 只能通过以下方式获取实例:

Console console = System.console();

⚠️ 注意:当你使用 Console 类时,若程序运行在 Eclipse 或 IntelliJ IDEA 等 IDE 中,则 JVM 关联的系统控制台不可用。

3. 输出功能对比

与 BufferedReader 和 Scanner 不同,Console 类提供了便捷的方法来向控制台输出提示信息,如:

  • readPassword(String fmt, Object… args)
  • readLine(String fmt, Object… args)
  • printf(String format, Object… args)

这使得我们可以省去手动调用 System.out.println 来打印提示语:

String firstName = console.readLine("Enter your first name please: ");
console.printf("Welcome " + firstName );

✅ 如果你在编写一个需要与系统控制台交互的程序,那么 Console 类会让你的代码更加简洁。

4. 解析输入的能力

Scanner 提供了强大的解析能力,可以按正则表达式将输入拆分为 token,默认以空白字符为分隔符:

String input = "Bufferedreader vs Console vs Scanner";
Scanner sc = new Scanner(input).useDelimiter("\\s*vs\\s*");
System.out.println(sc.next());
System.out.println(sc.next());
System.out.println(sc.next());
sc.close();

相比之下,BufferedReader 和 Console 只是原样读取输入流,不做额外处理。

5. 安全数据读取

Console 提供了两个方法用于安全输入(关闭回显):

  • readPassword()
  • readPassword(String fmt, Object… args)

比如读取密码:

String password = String.valueOf(console.readPassword("Password :"));

❌ 而 BufferedReader 和 Scanner 并不具备这个能力。

6. 线程安全性

  • BufferedReader 的 read 方法是 synchronized
  • Console 的 read 和 write 方法也是 synchronized
  • ❌ Scanner 的相关方法 不是线程安全的

✅ 因此,在多线程环境下读取用户输入时,优先考虑 BufferedReader 或 Console。

7. 缓冲区大小

  • BufferedReader 的缓冲区默认为 8KB
  • Scanner 的缓冲区只有 1KB
  • BufferedReader 支持自定义缓冲区大小,适用于读取大段文本
  • Console 在读取时不使用缓冲区,但在写入时使用了带缓冲的输出流

8. 其他细节差异

虽然这些点不构成选型的主要依据,但仍然值得关注。

8.1. 流关闭操作

  • 创建 BufferedReader 或 Scanner 后,必须手动关闭以避免内存泄漏
  • Console 则无需手动关闭

8.2. 异常处理机制

  • Scanner 和 Console 使用的是非检查型异常(unchecked exception)
  • BufferedReader 的方法抛出的是检查型异常(checked exception),强制你写 try-catch

9. 总结:如何选择?

以下是一些实用建议,帮助你根据不同场景做出合理选择:

使用 BufferedReader 的情况:

  • 从文件中读取长文本(性能更好)

使用 Console 的情况:

  • 从系统控制台读取敏感信息(如密码),并希望隐藏输入内容

使用 Scanner 的情况:

  • 需要对输入进行正则匹配或类型解析
  • 与控制台交互且不需要线程安全时(因其 API 更灵活)

多线程场景下:

  • 优先使用 BufferedReader(除非必须使用 Console 特性)

📌 总之,没有“最好的”工具,只有“最合适的”。理解它们各自的优缺点,才能写出更高效、健壮的代码。


原始标题:BufferedReader vs Console vs Scanner in Java