Cả hai đều dùng để đọc input, nhưng thiết kế cho mục đích khác nhau.
Bảng so sánh
| STT | Tiêu chí | Scanner | BufferedReader |
|---|---|---|---|
| 1 | Package | java.util |
java.io |
| 2 | Chức năng chính | Parsing: đọc + phân tích (parse) primitive, String, regex. | Đọc: chỉ đọc text (character stream), buffer lớn. |
| 3 | Buffer size | Nhỏ (~1KB char buffer). | Lớn (mặc định 8KB byte buffer, có thể tùy chỉnh). |
| 4 | Thread-safety | Không thread-safe. Chỉ dùng single-thread. | Thread-safe (synchronized methods). Dùng được multi-thread. |
| 5 | Tốc độ | Chậm hơn (phân tích regex, locale). | Nhanh hơn (chỉ đọc, không parse). |
| 6 | API tiện ích | nextInt(), nextDouble(), nextLine(), hasNext(), useDelimiter(). |
readLine(), read(), read(char[]). Parse thủ công: Integer.parseInt(). |
| 7 | Encoding | Dùng charset mặc định hoặc set qua constructor. | Wrap InputStreamReader với charset cụ thể. |
| 8 | Đọc dòng | nextLine() (bỏ qua delimiter, trả về dòng). |
readLine() (trả về null khi EOF). |
| 9 | Resource management | Implement Closeable (Java 7+), dùng try-with-resources. |
Implement Closeable, dùng try-with-resources. |
Ví dụ so sánh
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class JavaTester {
public static void main(String args[]) throws IOException {
// BufferedReader - đọc dòng, parse thủ công
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
System.out.print("BufferedReader - Nhập số: ");
int a = Integer.parseInt(br.readLine());
System.out.println("Bạn nhập: " + a);
}
// Scanner - parse tự động
try (Scanner sc = new Scanner(System.in)) {
System.out.print("Scanner - Nhập số: ");
int b = sc.nextInt();
System.out.println("Bạn nhập: " + b);
}
}
}
Kết quả
BufferedReader - Nhập số: 1 Bạn nhập: 1 Scanner - Nhập số: 2 Bạn nhập: 2
Khi nào dùng nào?
Dùng Scanner khi: Input có cấu trúc, cần parse primitive (int, double), tokenize bằng delimiter/regex, code ngắn gọn, competitive programming, single-thread.
Dùng BufferedReader khi: Đọc file lớn, đọc dòng (line-by-line), performance critical, multi-threaded environment, cần kiểm soát encoding, không cần parse phức tạp.
Hiệu năng: Đọc file lớn (100MB+ lines)
// BufferedReader - Nhanh nhất cho line-by-line
try (BufferedReader br = new BufferedReader(new FileReader("big.txt"))) {
String line;
while ((line = br.readLine()) != null) {
// process line
}
}
// Scanner - Chậm do regex parsing
try (Scanner sc = new Scanner(new File("big.txt"))) {
while (sc.hasNextLine()) {
String line = sc.nextLine();
}
}
// Java 8+ Files.lines() - Stream, lazy, parallelizable
try (Stream lines = Files.lines(Paths.get("big.txt"))) {
lines.parallel().forEach(line -> { /* process */ });
}
Lưu ý thường gặp
Scanner.nextInt()không consume newline →nextLine()sau đó đọc rỗng. Fix: gọi thêmsc.nextLine()sau nextInt().BufferedReader.readLine()trả vềnullkhi EOF (khác""dòng rỗng).Scannerdùng regex làm delimiter mặc định là whitespace (\\p{javaWhitespace}+).- Để đọc password (không echo):
Console console = System.console(); char[] pwd = console.readPassword();(không dùng Scanner/BufferedReader).
Tóm tắt
| Scenario | Khuyên dùng |
|---|---|
| Competitive Programming (stdin) | Scanner (code ngắn) hoặc BufferedReader + StringTokenizer (nhanh) |
| Đọc config file nhỏ | Scanner hoặc Files.readAllLines |
| Đọc log file lớn (GB) | BufferedReader hoặc Files.lines().parallel() |
| Multi-threaded server đọc socket | BufferedReader (thread-safe) |
| Parse CSV/JSON phức tạp | Thư viện chuyên biệt (Jackson, OpenCSV) - không dùng Scanner |