Java 언어를 사용해서 백준 문제를 풀고 있었는데, Scanner를 사용해서 입력을 받을 때는 시간 초과가 나고 BufferedReader를 사용하자 시간 초과 에러가 발생하지 않았다. 이 둘이 어떤 차이가 있는지 알아보자.
✅ 스트림
스트림(Stream)을 통해 값을 입력하고, 값을 출력할 수 있다. 스트림은 바이트(byte) 데이터를 읽고 출력하는 "바이트 기반 스트림"과 문자(char) 데이터를 읽고 출력하는 "문자 기반 스트림"으로 구분된다.
✅ 보조 스트림
"보조 스트림" 이란 다른 스트림과 연결되어 여러가지 편리한 기능을 제공하는 스트림이다.
- 자체적으로 입출력이 불가능하기 때문에 입출력 소스와 바로 연결과는 InputStream, OutputStream, Reader, Writer 등에 연결하여 입출력을 수행한다.
- 문자 변환, 입출력 성능 향상, 기본 타입 입출력 등의 기능을 제공한다.
- 보조 스트림을 연속적으로 연결할 수 있다 .
✔️ 문자 변환 보조 스트림
소스 스트림이 바이트 기반 스트림(InputStream, OutputStream, FileInputStream, FileOutputStream)이면서, 입출력 데이터가 문자일 경우 Reader와 Writer로 변환해서 사용하는 것이 편리하다.
OutputStreamWriter (OutputStream → Writer)
: 바이트 기반 출력 스트림에 연결되어 문자 출력 스트림인 Writer로 변환하는 보조 스트림
FileOutputStream fos = new FileOutputStream("file.txt");
Writer writer = new OutputStreamWriter(fos);
InputStreamReader (InputStream → Reader)
: 바이트 기반 입력 스트림에 연결되어 문자 입력 스트림인 Reader로 변환하는 보조 스트림 (byte → char)
// 키보드 입력
InputStream is = System.in;
Reader r = new InputStreamReader(is);
// 파일 입력
FileInputStream fis = new FileInputStream("file.txt");
Reader r = new InputStreamReader(fis);
✔️ 성능 향상 보조 스트림
메모리 버퍼를 추가로 제공하여 프로그램의 실행 성능을 향상한다.
BufferedOutputStream, BufferedWriter
- BufferedOutputStream : 바이트 기반 출력 스트림에 연결
- BufferedWriter : 문자 기반 출력 스트림에 연결
- 프로그램에서 전송한 데이처를 내부 버퍼에 쌓아두었다가 버퍼가 꽉 차면, 버퍼의 모든 데이터를 한번에 보냄
BufferedInputStream, BufferedReader
: 프로그램은 외부 소스로부터 직접 읽는 것이 아닌 버퍼로부터 읽음으로써 읽기 성능이 향상된다.
- BufferedInputStream : 바이트 기반 입력 스트림에 연결
- BufferedReader : 문자 기반 입력 스트림에 연결
- readLine() : 줄 바꿈을 기준으로 파일을 읽는다.
- 더 이상 읽을 라인이 없으면 null을 리턴한다.
✅ BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 정수 입력 : ex) "4"
n = Integer.parseInt(br.readLine());
// 배열 입력 : ex) "1 2 3 4"
StringTokenizer st;
arr = new int[n];
for(int i=0; i<n; i++){
st = new StringTokenizer(br.readLine(), " "); // 공백으로 구분
arr[i] = Integer.parseInt(st.nextToken());
}
해당 코드에서는 보조 스트림이 2개가 사용된다. 문자 변환 보조 스트림인 "InputStreamReader"를 활용하여 byte -> char로 변환해주고, 성능 향상 보조 스트림인 "BufferedReader"를 활용하여 버퍼를 통한 읽기 성능 향상을 기대할 수 있다.
//키보드에서 byte 타입으로 입력 받음
InputStream is = System.in;
// byte → char로 변환
InputStreamReader isr = new InputStreamReader(is);
//버퍼를 통한 읽기 성능 향상
BufferedReader br = new BufferedReader(isr);
✅ Scanner
Scanner sc = new Scanner(System.in);
// 정수 입력 : ex) "1"
int n = sc.nextInt();
// 배열 입력 : ex) "1 2 3 4"
int[] arr = new int[4];
for(int i=0; i<arr.length; i++){
arr[i] = sc.nextInt();
}
- Scanner는 BufferedReader와 달리 오버로딩을 통해 어떤 형태의 스트림이던간에 내부적으로 알아서 처리하도록 설정되어 있다. 그리고 nextInt(), nextDouble()과 같은 편의성 기능을 제공한다. 이러한 변환 과정과 정규식으로 올바른 형태인지 판단하는 과정에서 시간이 소요된다.
- 버퍼 기능이 없어서 읽기가 느리다.
참고
https://velog.io/@kkimbj18/%EB%B2%84%ED%8D%BC%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-Feat.-BufferedReader-vs-Scanner-cache
'☕ Java' 카테고리의 다른 글
자바 실행 과정 (JVM) (2) | 2025.01.02 |
---|---|
PriorityQueue, Comparator (0) | 2024.12.12 |