백준 알고리즘 문제 [백준] 2566번 : 최댓값을 풀다가 Java의 Scanner와 BufferedReader의 차이에 대해 궁금해지게 되었다. 우선 문제의 코드부터 살펴보자.
첫 번째로 제출한 코드는 아래와 같다.
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int max = 0, row = 0, col = 0;
for (int i = 0; i < 9; i++) {
String line[] = br.readLine().split(" ");
for (int j = 0; j < 9; j++) {
int val = Integer.parseInt(line[j]);
if (max <= val) {
max = val;
row = i + 1;
col = j + 1;
}
}
}
System.out.println(max);
System.out.println(row + " " + col);
}
}
이렇게 제출하고서 br.readLine().split(" "), Integer.parseInt(line[j])의 코드가 번잡스럽게 느껴져 BufferedReader가 아닌 Scanner를 통해 sc.nextInt() 한 줄로만 값을 받게끔 하면 어떨까 싶었다.
import java.io.*;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
int max = 0, row = 0, col = 0;
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
int val = sc.nextInt();
if (max <= val) {
max = val;
row = i + 1;
col = j + 1;
}
}
}
System.out.println(max);
System.out.println(row + " " + col);
}
}
둘 다 통과 처리된 데에는 문제가 없었지만, BufferedReader를 사용했을 때(아래)와 Scanner를 사용했을 때(위)의 메모리 사용량과 소요시간에 생각보다 큰 차이가 있음을 느꼈다.

그럼 이제 Scanner와 BufferedReader에 대해 각각 비교해서 알아보자.
Scanner 클래스는 입력받은 데이터(바이트)를 다양한 타입으로 변환하여 반환하는 클래스이다. 간단하게 기본형과 String 타입을 정규표현식을 사용해 파싱(parse)할 수 있다.
Scanner의 특징java.util 패키지에 속한다. (java.util.Scanner)1024byte(1KB)이다.UnChecked(Runtime) Exception으로 별도로 예외 처리를 명시할 필요가 없다.Thread unsafe 성질을 지니기에 멀티스레드 환경에서 문제가 발생할 수 있다.데이터를 한번에 읽어와 버퍼에 보관한 후 버퍼에서 데이터를 읽어오는 방식으로 동작하는 클래스이다. 즉 사용자가 입력한 문자 스트림을 읽는 것(read) 라고 한다.
BufferedReader의 특징java.io 패키지에 속한다. (java.io.BufferedReader)String으로만 읽고 가져온다.8192byte(8KB)이다.Checked Exception으로 반드시 예외 처리를 명시해야한다.(I/O Exception을 throw하거나 try/catch 해야한다.)Thread safe 성질을 지니기에 멀티스레드 환경에서도 안전하다.Scanner보다 소요되는 시간을 절약할 수 있다.BufferedReader를 사용할때와 Scanner의 속도가 차이가 나는 이유는 버퍼 사용 여부의 차이이다. Scanner는 1KB 크기의 버퍼를 갖기 때문에 입력이 바로 전달되는 반면, BufferedReader는 8KB 크기의 버퍼를 가져 버퍼에 입력들을 저장했다가 한 번에 전송하기 때문에 Scanner에 비해 속도가 더 빠르다. 또한, Scanner는 입력을 읽는 과정에서 내부에서 정규 표현식 적용, 입력값 분할, 파싱 과정 등을 거치기 때문에 속도가 느리다.

둘의 차이에 대해 정리하자면 다음과 같다.
Scanner는 BufferedReader보다 타입에 구애받지 않는다.BufferedReader는 String 형식으로만 읽고 저장하기에 형변환을 위한 추가적인 코드 작성이 불가피한 반면에 Scanner는 원하는 타입으로 읽고 파싱할 수 있다.Scanner의 경우 int, long, short, float, double의 경우 nextInt(), nextLong(), nextShort(), nextFloat(), nextDouble()과 같은 함수들을 사용할 수 있다.BufferedReader는 readLine() 함수만을 사용한다.BufferedReader는 Scanner보다 효율적인 메모리 용량을 가진다.BufferedReader의 버퍼 메모리가 8KB로 Scanner의 버퍼 메모리 1KB보다 크기에 많은 입력이 있을 경우 더 효율적이다.BufferedReader의 경우 일단 큰 메모리를 잡아먹게 된다.BufferedReader는 Scanner보다 안전하다.Scanner는 Thread-unsafe 하기에 멀티스레드 환경에서 안전하지 않지만 BufferedReader는 안전하다.Scanner는 공유할 수 없지만 BufferedReader는 공유할 수 있다. 동기화를 지원하는 BufferedReader는 싱글스레드인 Scanner보다 약간 느리긴 하지만, Scanner의 경우 정규식을 사용하여 입력을 받으므로 BufferedReader가 문자열을 더욱 빠르게 입력받을 수 있다.BufferedReader가 Scanner보다 실행 속도가 빠르다.Scanner보다 버퍼에 어느정도 쌓아두고 가득차거나 개행이 일어날 때마다 입출력을 처리하는 BufferedReader가 훨씬 효율적이다.