[Java] 입력 속도 향상 - BufferedReader

SHY DEV·2024년 1월 29일
0

Java X Algorithm

목록 보기
2/7
post-thumbnail

이 글에서는 java 에서 입력 속도를 향상시켜주는 BufferedReader에 대해 알아봅니다.


입력 속도 향상 기법의 중요성

  • 일상적인 개발에서는 사용 편의성을 우선시하는 느린 입력 방법이 자주 사용됩니다. 하지만, 입력이 매우 많이 반복되는 경우에는 편의성보다는 속도에 중점을 둔 빠른 처리 방법이 필요합니다. 각 상황에 맞는 입력 처리 방법을 익힌다면 효율적인 프로그램을 작성 할 수 있습니다.

  • 알고리즘 문제를 해결하다 보면 핵심 로직은 동일한데 입력 처리 방식 차이로 인해 시간 초과인지 성공인지 갈리는 경우가 종종 있습니다. 만약 입력에서 시간이 지연되었음을 파악하지 못한다면 로직에서 문제를 찾는 헛수고를 하게 됩니다.


입력 속도 문제

  • java를 처음 배우면 대부분 사용자 입력을 받을 때 Scanner를 알려줍니다.
	Scanner sc = new Scanner(System.in);
    int N = sc.nextInt();
  • Scanner가 사용법이 간단하고 편리한 기능을 많이 제공해 주기 때문입니다. 하지만 알고리즘 문제를 풀다 보면 처리 시간을 극한으로 줄여야 하는 경우가 존재하는데, 그때 Scanner를 통해 입력 처리를 한다면 대부분 시간 초과가 발생합니다.
  • Scanner 클래스를 통해 입력된 값을 nextInt(), nextLine() 등의 메서드로 받아올 때, 내부적으로 복잡한 정규 표현식을 사용해 처리 시간이 긴 편이기 때문입니다.

입력 속도 향상: BufferedReader

  • BufferedReader는 버퍼를 사용해 입력 성능을 향상시키는 보조 스트림입니다.
  • 사용법
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String line = br.readLine();  // 한 줄 단위로 읽기
  • 주로readLine()메서드로 한 줄 단위로 입력받아 가공합니다. 가공을 고의적으로 느리게 하지 않는 이상 입력, 가공 시간을 합쳐도 Scanner에 비해 훨씬 빠릅니다.

버퍼

  • 버퍼는 데이터를 임시로 저장하는 메모리 영역입니다.

    도서관에서 여러 권의 책을 가져와야 하는 상황에서 가방을 사용한다면 여러 권의 책을 담아 집으로 옮겨올 수 있습니다. 이때 가방버퍼로 비유할 수 있습니다.

    책을 하나씩 집으로 옮기는 것보다, 한 번 도서관에 갔을 때 많은 양의 책을 가방에 담아 옮기면 훨씬 효율적으로 책을 옮길 수 있듯, 버퍼를 사용하면 데이터를 읽는 횟수가 줄어 입력을 빠르게 처리할 수 있습니다.

  • 사실 Scanner도 버퍼를 사용하는데요, BufferedReader의 버퍼에 비하면 작은 사이즈입니다.
	/* Scanner 클래스의 버퍼 크기 */
    private static final int BUFFER_SIZE = 1024;
    
    
    /* BufferedReader 클래스의 버퍼 크기 */
    private static final int DEFAULT_CHAR_BUFFER_SIZE = 8192;

보조 스트림

  • java에서는 데이터를 외부(파일, 키보드, 콘솔 등)로부터 가져오거나 내보낼 때 노드 스트림이 반드시 존재해야 합니다.
  • 이때 효율을 높이거나 부가적인 기능을 사용하기 위해 노드 스트림에 장착하는 추가적인 스트림을 보조 스트림 이라 합니다.

    집에서 물을 사용하고 싶다면 물이 존재하는 곳과 집을 연결하는 수도관을 필수로 연결해야 합니다. 그냥 물을 마시는 것을 넘어 따뜻한 물을 사용하고 싶다면 보일러를, 깨끗한 물을 사용하고 싶다면 필터를 설치합니다. 이때 수도관노드 스트림, 보일러와 필터보조 스트림으로 비유할 수 있습니다.

  • 이 개념을 통해 BufferedReader를 생성한 부분의 코드를 이해할 수 있습니다.
	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  1. System.in : 키보드로부터 데이터를 입력받기 위해 필수로 존재해야하는 노드 스트림입니다.

  2. InputStreamReader(System.in) : 바이트 기반으로 데이터를 읽어오는 스트림을 문자 기반 데이터로 읽어올 수 있도록 업그레이드하는 보조 스트림인InputStreamReader
    System.in에 장착한 것입니다. 이제 키보드로부터 문자 데이터를 읽어오는 스트림이 형성되었습니다.

  3. BufferedReader(new InputStreamReader(System.in)) : 키보드로부터 문자 데이터를 읽어오는 스트림에 버퍼 기능까지 탑재하였습니다.


BufferedReader 사용 예시

  • 백준 온라인 저지 사이트의 7576번 토마토 문제의 입력값을 BufferedReader로 받아오는 코드를 예시로 보여드리며 마무리하겠습니다.

문제 링크: https://www.acmicpc.net/problem/7576

입력 조건:

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다.
M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다.
단, 2 ≤ M,N ≤ 1,000 이다.
둘째 줄부터는 하나의 상자에 저장된 토마토들의 정보가 주어진다.
즉, 둘째 줄부터 N개의 줄에는 상자에 담긴 토마토의 정보가 주어진다.
하나의 줄에는 상자 가로줄에 들어있는 토마토의 상태가 M개의 정수로 주어진다.
정수 1은 익은 토마토, 정수 0은 익지 않은 토마토,
정수 -1은 토마토가 들어있지 않은 칸을 나타낸다.

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] line = br.readLine().split(" ");
int M = Integer.parseInt(line[0]);
int N = Integer.parseInt(line[1]);

int[][] box = new int[N][M];
for (int n = 0; n < N; ++n) {
	line = br.readLine().split(" ");
    for (int m = 0; m < M; ++m) {
    	box[n][m] = Integer.parseInt(line[m]);
    }
}
  • BufferedReader의 사용은 어렵지 않습니다. readLine() 메서드를 통해 한 줄 단위로 읽어오는 것이 전부입니다. 이후 원하는 형태로의 가공은 문자열 및 형 변환 등을 학습한 후 조금만 연습하다 보면 금방 익숙해질 수 있습니다.
profile
서로의 발전을 위해 정리하고 공유합니다. 피드백 환영합니다.

0개의 댓글