[Java] Scanner vs BufferedReader

develemon·2024년 3월 1일
0

Java

목록 보기
2/3
post-thumbnail

Intro


백준 알고리즘 문제 [백준] 2566번 : 최댓값을 풀다가 Java의 ScannerBufferedReader의 차이에 대해 궁금해지게 되었다. 우선 문제의 코드부터 살펴보자.

첫 번째로 제출한 코드는 아래와 같다.

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를 사용했을 때(위)의 메모리 사용량소요시간에 생각보다 큰 차이가 있음을 느꼈다.

그럼 이제 ScannerBufferedReader에 대해 각각 비교해서 알아보자.

java.util.Scanner


Scanner 클래스는 입력받은 데이터(바이트)를 다양한 타입으로 변환하여 반환하는 클래스이다. 간단하게 기본형과 String 타입을 정규표현식을 사용해 파싱(parse)할 수 있다.

Scanner의 특징

  • java.util 패키지에 속한다. (java.util.Scanner)
  • 공백(띄어쓰기) 및 개행(줄 바꿈)을 기준으로 읽는다.(' ', '\t', '\r', '\n' 등)
  • 원하는 타입으로 읽을 수 있다.
  • 버퍼의 사이즈가 1024byte(1KB)이다.
  • UnChecked(Runtime) Exception으로 별도로 예외 처리를 명시할 필요가 없다.
  • Thread unsafe 성질을 지니기에 멀티스레드 환경에서 문제가 발생할 수 있다.
  • 데이터를 입력받을 경우 즉시 사용자에게 전송되며 입력받을 때마다 전송되어야 하기에 많은 시간이 소요된다.

java.io.BufferedReader


데이터를 한번에 읽어와 버퍼에 보관한 후 버퍼에서 데이터를 읽어오는 방식으로 동작하는 클래스이다. 즉 사용자가 입력한 문자 스트림을 읽는 것(read) 라고 한다.

BufferedReader의 특징

  • java.io 패키지에 속한다. (java.io.BufferedReader)
  • 데이터를 파싱하지 않고 String으로만 읽고 가져온다.
  • 버퍼의 사이즈가 8192byte(8KB)이다.
  • Checked Exception으로 반드시 예외 처리를 명시해야한다.(I/O Exception을 throw하거나 try/catch 해야한다.)
  • Thread safe 성질을 지니기에 멀티스레드 환경에서도 안전하다.
  • 버퍼가 가득차거나 개행문자가 나타나면 버퍼의 내용을 한번에 프로그램으로 전달하기에 Scanner보다 소요되는 시간을 절약할 수 있다.

Scanner와 BufferedReader의 차이


BufferedReader를 사용할때와 Scanner의 속도가 차이가 나는 이유는 버퍼 사용 여부의 차이이다. Scanner1KB 크기의 버퍼를 갖기 때문에 입력이 바로 전달되는 반면, BufferedReader8KB 크기의 버퍼를 가져 버퍼에 입력들을 저장했다가 한 번에 전송하기 때문에 Scanner에 비해 속도가 더 빠르다. 또한, Scanner는 입력을 읽는 과정에서 내부에서 정규 표현식 적용, 입력값 분할, 파싱 과정 등을 거치기 때문에 속도가 느리다.

둘의 차이에 대해 정리하자면 다음과 같다.

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

참고자료


  1. Scanner vs BufferedReader
  2. 자바(JAVA) - Scanner & BufferedReader
profile
유랑하는 백엔드 개발자 새싹 블로그

0개의 댓글