Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Java

Sự khác biệt giữa Scanner và BufferedReader trong Java

Cả hai đều dùng để đọc input, nhưng thiết kế cho mục đích khác nhau.

Bảng so sánh

STTTiêu chíScannerBufferedReader
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êm sc.nextLine() sau nextInt().
  • BufferedReader.readLine() trả về null khi EOF (khác "" dòng rỗng).
  • Scanner dù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

ScenarioKhuyê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 socketBufferedReader (thread-safe)
Parse CSV/JSON phức tạpThư viện chuyên biệt (Jackson, OpenCSV) - không dùng Scanner