들어가며
코딩테스트의 기초부터 학습하고 있는 와중 기존 사용하던 Scanner와 이를 활용한 System.out,print가 아닌 보다 향상된 입출력 속도를 위해 BufferedReader와 BufferedWriter를 학습할 필요성을 느꼈다. 이전 한차례 포스트를 통해 정리했던 적이 있으나 이 기회에 다시금 정리하며 기초를 다지고자 한다.
A+B - 8
설명
두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.
입력
첫째 줄에 테스트 케이스의 개수 T가 주어진다.
각 테스트 케이스는 한 줄로 이루어져 있으며, 각 줄에 A와 B가 주어진다.(0 < A, B < 10)
출력
각 테스트 케이스마다 "Case #x: A + B = C" 형식으로 출력한다. x는 테스트 케이스 번호이고 1부터 시작하며, C는 A+B이다.
예제 입력1
5
1 1
2 3
3 4
9 8
5 2
예제 출력1
Case #1: 1 + 1 = 2
Case #2: 2 + 3 = 5
Case #3: 3 + 4 = 7
Case #4: 9 + 8 = 17
Case #5: 5 + 2 = 7
풀이1
먼저 기존 하던 방식대로 Scanner 및 System.out.print를 활용하여 문제를 해결해 보았다.
import java.util.Scanner;
public class Main {
/* A+B - 8 */
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int T = scanner.nextInt();
for (int i = 1; i < T+1; i++) {
int A = scanner.nextInt();
int B = scanner.nextInt();
int sum = A + B;
System.out.println("Case #" + i + ": " + A + " + " + B + " = " + sum);
}
scanner.close();
}
}
왜 Scanner, System.out.print 보다 BufferedReader, BufferedWriter가 더 빠를까?
BufferedReader와 BufferedWriter를 적용하여 리팩터링 하기 이전, 왜 이 둘이 기존에 사용하던 것들 보다 빠른지에 대한 의문부터 해결할 필요가 있다.
BufferedReader 와 BufferedWriter 는 이름에서 알 수 있듯 버퍼를 사용하여 입출력을 하는 함수이다.
Scanner와 같이 버퍼를 사용하지 않는 입력은 키보드 등의 입력장치의 키를 누르는 즉시 프로그램에 전달된다.
반면 BufferedWriter와 같이 버퍼를 사용하는 입력은 입력장치를 통한 입력이 발생할 때 마다 한 문자씩 버퍼로 전송시킨다. 그리고 버퍼가 가득 차거나 개행 문자가 나타나야 버퍼의 내용을 한 번에 프로그램에 전달한다.
위 문장만 들었을 때는 버퍼에 문자를 모아 출력하는 것 보다, 키보드의 입력을 받는 즉시 출력하는 것이 더 빠른 것이 아닐까란 의문이 들 수 있다. 하지만 생각보다 하드디스크의 속도는 느리다. 그리고 외부 입출력 장치(키보드, 모니터 등)와 데이터가 입출력 될 때까지의 시간 소요도 크다. 그렇기에 입력이 발생할 때 마다 바로바로 이동시키는 것 보다, 중간에 버퍼를 두어 데이터를 묶어 한 번에 내보내는 것이 훨씬 빠르고 효과적인 것이다.
물건을 옮긴다고 가정하였을 때, 물건을 하나씩 들고 옮기는 것보다 트럭에 실고 한 번에 옮기는 것이 훨씬 효율적인 것과 같은 이치이다.
BufferedReader, BufferedWirter 사용법
BufferedReader와 BufferedWirter를 사용하기 위해서는 먼저 아래와 같이 import 부터 해줄 필요가 있다.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
//이를 묶어 아래 하나로 묶어줄 수도 있다.
import java.io.*;
BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //선언
String str = br.readLine(); //String
int i = Integer.parseInt(bf.readLine()); //Int
선언은 위 예제처럼 진행하면 된다.
입력은 readLine() 메서드를 사용하여, 사용 시 두 가지 주의점이 있다.
첫 번째는 readLine() 메서드이 return 값은 String으로 고정되기에 다른 타입으로의 입력을 받기 위해서는 형 변환 작업을 꼭 거쳐주어야한다는 것이다.
(Integer.parseInt()와 같이)
두 번째는 예외처리를 꼭 해주어야 한다는 점이다. readLine()을 할 때 마다 try & catch를 사용해 예외처리를 해주어도 되지만 보통은 IOException을 활용한다.
IOException을 통한 입출력 예외처리 방법
1. 추가적인 import 필요
import java.io.IOException;
2. 메인 메서드에 throws IOException 작성
public static void main(String[] args) throws IOException {
}
StringTokenizer
BufferedReader의 readLine()을 통해 얻은 데이터는 Line 단위로만 나눠지기에, 공백 단위로 데이터를 가공하기 위해서는 추가적인 작업이 필요하다.
String 클래스의 split() 메서드를 사용하는 방법도 있지만 편의상 StringTokenizer 클래스를 사용하는 방법을 주로 활용한다.
StringTokenizer를 사용하면 입력받은 데이터를 공백 단위로 구분하여 순서대로 호출하는 것이 가능해진다.
앞서 설명한 BufferReader와 함께 사용하는 방법은 아래와 같다.
import java.util.StringTokenizer; //import 필요
...
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //선언
String str = br.readLine(); //String
StringTokenizer st = new StringTokenizer(str); //StringTokenizer인자값에 입력 문자열 넣음
int a = Integer.parseInt(st.nextToken()); //첫번째 호출
int b = Integer.parseInt(st.nextToken()); //두번째 호출
BufferedWriter
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); //할당된 버퍼에 값 넣어주기
String str = "abcdefg"; //출력할 문자열
bw.write(s+"\n"); //출력 + 줄바꿈
bw.newLine(); //줄바꿈
bw.flush(); //남아있는 데이터를 모두 출력시킴
bw.close(); //스트림을 닫음
BufferedWriter는 System.out.println과 유사하지만 사용에 있어 두 가지 유의사항이 있다.
첫 번째는 BufferedWriter는 이름에서도 알 수 있듯 버퍼를 잡아 놓기에 사용 후 flush()와 close()를 해주어야 한다는 것이다.
두 번째는 BufferedWriter의 경우 System.out.println과 달리 출력과 개행을 동시에 해주지 않기에 줄바꿈을 위해서는 입력값에
+ "\n" 을 덧붙여주거나 newLine() 메서드를 사용하여야한다.
Solution.java
package baekjoon;
import java.io.*;
import java.util.StringTokenizer;
public class baekjoon11022 {
/* A+B - 8 */
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
for (int i = 1; i < T + 1; i++) {
st = new StringTokenizer(br.readLine());
int A = Integer.parseInt(st.nextToken());
int B = Integer.parseInt(st.nextToken());
int sum = A + B;
bw.write(("Case #" + i + ": " + A + " + " + B + " = " + sum) + "\n");
}
bw.flush();
bw.close();
}
}
Reference
크크의 개발 블로그 - [Java] 빠른 입출력을 위한 BufferedReader, BufferedWriter, StringTokenizer, StringBuilder
Oh린이의 소확행 - [JAVA] BufferedReader와 BufferedWriter 사용법
'🤖Algorithm' 카테고리의 다른 글
[백준] 에라토스테네스의 체 (0) | 2023.01.25 |
---|---|
[인프런] 자바 알고리즘 문제풀이 단어 뒤집기 (0) | 2022.10.11 |
[백준] 2741 N찍기 Java (0) | 2022.08.04 |
[백준] 15552 빠른 A+B Java (0) | 2022.08.01 |
[백준] 2480 주사위 세개 Java (0) | 2022.07.30 |