[Java]Scanner 대신 BufferedReader??

Ceing·2024년 6월 19일

Java

목록 보기
3/8
post-thumbnail

개요

  • 자바에서의 입력은 두 가지 객체를 통해 받을 수 있다

  • 하나는 Scanner 하나는 BufferedReader이다

  • 둘은 매우 극명한 차이를 보인다


백준 : 11382

Scanner 풀이


BufferedReader 풀이


결과

  • 위의 결과가 Scanner 풀이이고, 아래의 결과가 BufferedReader 풀이이다.

  • 입력을 3개 밖에 받지 않는 매우 간단한 문제에서도 이와 같은 속도 차이를 볼 수 있음에 따라 BufferedReader의 성능이 압도적으로 좋다는 사실을 알 수 있다.

  • 왜 이런 성능 차이가 생기는지 지금부터 확인해보자



BufferedReader 개념 및 Scanner와의 차이

  • 이름에서도 알 수 있듯 버퍼를 통해 입력을 받을 수 있는 api를 제공하는 클래스이다.

  • 즉 입력값들을 버퍼라는 공간에 모아놓고 출력 시점에 한꺼번에 출력이 된다는 뜻이다.

  • 이런 질문이 있을 수 있다. "아니 근데 한꺼번에 모아놓고 출력하면 더 느려야되는데 왜 빠름요??"

  • 간단하게 예를 들어주겠다.

  • 청소를 할때 우리는 쓰레기를 한꺼번에 모아서 버리는 것이 훨씬 빠르고 효율적이라는 것을 본능적으로 알 것이다.

  • 그 이유는 쓰레기를 버리러 "왔다갔다"하는 시간을 줄일 수 있기 때문이다.

  • 프로그래밍 관점에서도 똑같다.

  • 우리는 입출력을 할 때 외부 스트림을 연결해서 입력을 받고 출력을 한다.

  • 하지만 이 작업을 입력 하나하나당 해버리면 결국 성능적으로 손해를 보게 된다.

  • Scanner이 그런 친구이다. Scanner로 입력을 받으면 매 입력마다 곧바로 애플리케이션으로 가져오므로 버퍼에 모아놓고 출력 시점에 전부 애플리케이션에 할당하는 BufferedReader와 성능 차이가 존재하는 것이다.



BufferedReader API

BufferedReader 객체 생성

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

입력 api

입력 api로는 두 가지가 있다.

  1. br.readLine()
  2. br.read()

1. br.read();

  • 입력을 한 아스키코드의 문자로 받을 수 있음

  • 즉 한 자리수의 char 또는 int를 입력받을 때 좋음

  • 여러 개의 값을 입력받는다 한들 맨 앞 한 글자만 인식되고 나머지는 무시됨


2. br.readLine()

  • BufferedReader api의 핵심

  • 엔터를 입력값 간의 경계로 인식

  • 문자열로만 데이터 인식

  • 즉 다른 형태의 입력을 받기 위해선 파싱 작업을 별도로 해주어야 하고 스페이스 단위로 입력을 받기 위해선 별도의 작업이 필요함


주의사항 : IOException 처리

  • 외부 파일과의 입출력 작업은 반드시 IOException 예외를 처리해줘야됨

  • 일반적으로 메서드 시그니쳐에 throws 키워드로 IOException 예외를 상위 영역에 던지는 형태로 작성 가능



BufferedReader와 함께 사용하는 유용한 api

스페이스 단위의 입력 : StringTokenizer api

입력 : 1 2 3 , 출력 5 6 7

  • 이런 형태로 입력을 스페이스 단위로 받아야하는 경우가 많음

  • 하지만 BufferedReader은 엔터 단위의 입력만 가능하므로 BufferedReader와 StringTokenizer을 혼합해서 써줄 수 있음

  • StringTokenizer 생성자는 파라메터로 ① 토큰과 ② 구분자를 넘겨줄 수 있음

  • 이때 토큰은 쪼갤 문자열 단위이고, 구분자는 말 그대로 문자열을 구분짓기 위한 단위임

  • 디폴트로 공백이고 / , . - 등 원하는 구분자를 문자열 형태로 지정할 수 있음

 StringTokenizer st = new StringTokenzier(br.readLine() , " ");
  • 입력받은 문자열들을 " "공백 구분자로 구분 지어서 쪼개진 문자열들을 하나의 토큰으로 인식할 수 있음
  • 각각의 토큰은 처음부터 nextToken()을 통해 접근 가능

다른 타입으로 파싱 : 포장 클래스 api

  • 예를 들어 정수형으로 파싱한다고 치자
  • 정수형 포장 클래스인 Integer는 문자열을 자신의 타입으로 파싱시켜주는 api인 parseInt()를 제공
  • 즉 Integer.parseInt(입력 값)을 통해 입력 받은 문자열을 정수형으로 변환해줄 수 있음


실전

문제 : 1 2 3 형태로 숫자들을 띄어쓰기로 구분지어서 3개를 입력 받아서 각각의 수에 100을 더한 수를 차례대로 출력하기

BufferedReader br  = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
System.out.println((a += 100) + " " + (b += 100) + " " + (c += 100));

✰ 이런 식으로 BuffereddReader + StringTokenizer을 활용할 수 있음

profile
이유에 대해 끊임없이 생각하고 고민하는 개발자

0개의 댓글