
자바(Java)를 처음 접하면 가장 먼저 배우는 것 중 하나가 콘솔 입력입니다. 이때 우리는 보통 Scanner를 사용하곤 합니다. 하지만 알고리즘 문제를 풀거나 대용량 데이터를 처리하는 현업 프로젝트에 투입되면 "왜 BufferedReader를 써야 하는가?"라는 질문을 마주하게 됩니다. 단순히 '빠르다'는 이유를 넘어, 두 클래스가 내부적으로 어떻게 동작하며 어떤 상황에서 진가를 발휘하는지 전문적인 관점에서 심도 있게 분석해 보겠습니다.
1. 왜 입력 방식의 선택이 중요한가?
컴퓨터 시스템에서 I/O(Input/Output) 작업은 CPU 연산에 비해 압도적으로 느린 작업입니다. 표준 입력(System.in)으로부터 데이터를 읽어올 때, 매번 한 바이트씩 가져오느냐 아니면 한꺼번에 뭉텅이로 가져와 메모리에 올려두고 쓰느냐의 차이는 프로그램 전체의 처리 속도를 결정짓는 핵심 요소가 됩니다.
2. Scanner와 BufferedReader의 핵심 메커니즘 차이
Scanner: 편의성을 위한 다목적 파서(Parser)
Scanner는 단순히 읽어오는 도구가 아니라, 읽어온 데이터를 정수, 실수, 문자열 등으로 즉시 변환해주는 파싱 기능이 내장되어 있습니다. 정규 표현식을 사용하여 구분자(Delimiter)를 기준으로 데이터를 쪼개기 때문에 사용하기는 매우 편리하지만, 그만큼 오버헤드가 발생합니다.
BufferedReader: 속도를 위한 효율적인 버퍼링
이름에서 알 수 있듯이 BufferedReader는 중간에 버퍼(Buffer)를 둡니다. 입력 소스에서 직접 데이터를 읽는 대신, 버퍼가 가득 찰 때까지 한꺼번에 읽어 메모리에 저장합니다. 프로그램은 메모리에 있는 데이터를 읽기만 하면 되므로 시스템 콜(System Call) 횟수가 줄어들어 성능이 비약적으로 향상됩니다.
3. 상세 비교 분석표
| 비교 항목 | Scanner | BufferedReader |
|---|---|---|
| 버퍼 크기 | 1 KB | 8 KB (대용량 처리에 유리) |
| 동기화(Synchronization) | 비동기 (멀티스레드 환경에서 위험) | 동기화 지원 (Thread-safe) |
| 데이터 타입 변환 | nextInt(), nextDouble() 등 자동 변환 | String으로만 읽음 (수동 변환 필요) |
| 예외 처리 | RuntimeException (예외 처리 선택) | IOException (반드시 Checked Exception 처리) |
| 주요 용도 | 간단한 입출력, 타입별 데이터 파싱 | 대량 데이터 읽기, 성능 최적화 필수 상황 |
4. 실전 코드 예제 (Sample Example)
두 방식의 사용법 차이를 명확히 보여주는 예제입니다. 10개의 숫자를 입력받아 합을 구하는 간단한 로직입니다.
Case A: Scanner 사용
import java.util.Scanner;
public class ScannerExample {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("숫자 입력: ");
if (sc.hasNextInt()) {
int val = sc.nextInt();
System.out.println("입력된 값: " + val);
}
sc.close();
}
}
Case B: BufferedReader 사용 (성능 최적화 버전)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class BufferedReaderExample {
public static void main(String[] args) throws IOException {
// InputStreamReader를 통해 바이트 스트림을 문자 스트림으로 변환
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("문자열 입력: ");
String line = br.readLine(); // 한 줄 전체를 읽음
// 정수 변환이 필요할 경우 수동 파싱
// int number = Integer.parseInt(line);
System.out.println("출력 결과: " + line);
}
}
5. 결론: 무엇을 선택해야 할까?
전문 개발자의 관점에서 추천하는 선택 기준은 다음과 같습니다.
- 알고리즘 문제 풀이(PS): 0.1초 차이로 통과 여부가 결정되는 코딩 테스트에서는 무조건
BufferedReader를 사용하십시오. - 대규모 웹 어플리케이션: 로그 파일을 읽거나 외부 API의 대용량 응답을 처리할 때도 버퍼링이 적용된 스트림이 필수적입니다.
- 간단한 토이 프로젝트: 코드가 간결하고 직관적인
Scanner가 생산성 측면에서 유리할 수 있습니다.
결국 기술의 우열보다는 상황에 맞는 도구의 선택이 중요합니다. 입력 데이터의 크기와 처리 속도의 중요성을 고려하여 최적의 코드를 작성하시기 바랍니다.
출처 및 참고문헌
- Oracle Java Documentation: java.util.Scanner class
- Oracle Java Documentation: java.io.BufferedReader class
- Effective Java 3rd Edition (Joshua Bloch)
'Language > Java' 카테고리의 다른 글
| [JAVA] 외부 라이브러리 없이 JSON/XML 파싱하기 : 표준 API의 숨겨진 힘 (0) | 2026.01.20 |
|---|---|
| [JAVA] PrintStream vs PrintWriter : 당신의 출력 코드가 전문적인지 확인하는 법 (0) | 2026.01.20 |
| [JAVA] Java 파일 입출력의 진화: Legacy File 클래스 vs Modern NIO.2 완벽 분석 (0) | 2026.01.20 |
| [JAVA] serialVersionUID란 무엇인가요? 직렬화 버전 관리의 핵심 정리 (0) | 2026.01.20 |
| [JAVA] transient 키워드의 용도 : 직렬화에서 제외해야 할 데이터 관리법 (0) | 2026.01.20 |