오늘 학습한 내용
- Java : 예외 처리, 빠른 입출력(BufferedReader, BufferedWriter)
문제상황
오늘의 문제상황은 백준 프로그래밍 문제를 풀다가 발생했다

이제 조금 Scanner에 익숙해진 것 같다고 생각했는데..
Scanner는 입출력 방식이 느려서 많은 데이터를 입출력하는 경우에는 시간이 오래 걸릴 수 있다는 사실을 알았다..
그럴때는 위와 같이 BufferedReader, BufferedWriter를 사용하라고 하셨는데 이와 관련된 내용은 잘 모르기 때문에 이 부분에 대해서 공부를 하기로 했다.
문제링크는 다음과 같다.
https://www.acmicpc.net/problem/15552
15552번: 빠른 A+B
첫 줄에 테스트케이스의 개수 T가 주어진다. T는 최대 1,000,000이다. 다음 T줄에는 각각 두 정수 A와 B가 주어진다. A와 B는 1 이상, 1,000 이하이다.
www.acmicpc.net
시도한 내용
우선, Scanner를 이용해서 문제를 풀어보었다.
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int A = sc.nextInt();
for (int i=0; i<A; i++) {
int B = sc.nextInt();
int C = sc.nextInt();
System.out.println(B+C);
}
}
}
결과는 당연히..

실제로 buffer와 scanner가 얼마나 차이나는지 알기 위해서 검색을 해봤다.
https://www.acmicpc.net/blog/search/%EC%9E%85%EB%A0%A5+%EC%86%8D%EB%8F%84
위의 링크에서 buffer는 평균 0.6585, scanner는 4.8448초가 걸렸다. 거의 7배나 차이가 나는 것이다.
일단, Scanner를 쓰면 왜 느리고, Buffer를 사용하면 왜 빠른지 이해가 필요하다고 생각했다.

Scanner와 Buffer의 속도가 차이나는 이유는
- Scanner는 1KB 크기의 버퍼를 갖기 때문에 바로 입력이 전달된다.
- Scanner는 읽는 과정에서 내부에서 정규식, 입력값 분학, 파싱 과정 등을 거친다.
- BufferedReader는 8KB 크기의 버퍼를 가져서 buffer에 입력들을 저장했다가 한 번에 전송한다.
내가 이해한 내용으로는 물건을 한 개씩 옮기는 것보다는 상자에 담아서 한 번에 옮기는 것이 훨씬 빠른 것과 같은 것이라 생각했다.
이제 속도의 차이가 나는 이유에 대해서 알았으니 다음은 Buffer를 사용하는 방법에 대해서 공부하는 것이었다.
BufferedReader
- 입력 스트림에서 문자를 읽는 함수
- 문자나 배열, 라인들을 효율적으로 읽기 위해 문자들을 버퍼에 저장하고 읽는 방법을 취한다.
- readLine() 메소드를 이용하여 데이터를 줄 단위로 읽는다.
- 개행(엔터)만 경계로 인식하고 리턴값이 String으로 고정이다. (즉, 다른 타입으로 입력을 받으려면 형변환 필수!)
BufferedWriter
- 출력을 담당하는 함수
- 자동 개행 기능이 없기 떄문에 개행이 필요한 경우 '\n'을 통해서 처리해야 한다.
Buffer를 사용할때
- IOException의 예외처리가 필수적이다.
- 사용자의 입력은 여러 다양한 타입으로 들어올 수 있는데, 잘못된 값이 들어올 경우 에러가 발생할 수 있기 때문이다.
위의 내용을 토대로 로직을 작성했다.
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int A = Integer.parseInt(br.readLine());
for (int i=0; i<A; i++) {
String[] arr_str = br.readLine().split(" ");
int B = Integer.parseInt(arr_str[0]);
int C = Integer.parseInt(arr_str[1]);
bw.write(B+C);
bw.newLine();
}
bw.flush();
}
}
그런데 결과는

??! 결과는 원하는 대로 나오지 않았다.
거의 1시간 가까운 시간동안 여러가지를 시도해본 결과 bw.newLine말고 개행문자 "\r\n"을 사용하면 원하던 결과가 출력되는 것을 알게되었다.
계속 찾아봐도 정확한 사실은 알 수 없었다..
앞으로 개행이 필요한 경우에는 그냥 "\r\n"을 사용해야겠다..ㅎㅎ..
해결
학습한 내용을 토대로 작성한 코드는 다음과 같다.
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int A = Integer.parseInt(br.readLine());
for (int i=0; i<A; i++) {
String[] arr_str = br.readLine().split(" ");
int B = Integer.parseInt(arr_str[0]);
int C = Integer.parseInt(arr_str[1]);
bw.write(B+C+"\r\n");
}
bw.flush(); //bw.close() 해도 출력됨
}
}
결과는.. 두근두근..

2차 ??!
찾아보니 정답과 거의 유사한데, 공백, 빈 줄과 같은 문제로 인해서 출력 결과가 일치하지 않은 경우라고 한다..
혹시 몰라서 개행문자를 "\n"을 사용하니

다행히 통과가 되었따.. 백준 제출할때는 개행문자를 "\n"을 사용하쟈..
알게된 내용
문제를 풀 때 입력 받을 테스트 케이스가 10만개 이상이면 buffer를, 아니면 Scanner를 사용하는 연습을 하자.
새로운 사실을 알게 된다는건 언제나 신기하고 즐거운 일인 것 같다.
프로그래밍 공부하면서 정말 이런 경험을 많이 하는 것 같아서 정말 좋은 것 같다.
더욱 많이 배우고 성장하자 !!
참고
https://doozi316.github.io/java/2021/03/22/JAVA1/
https://dlee0129.tistory.com/238
'TIL&WIL' 카테고리의 다른 글
| 2023-05-30 TIL (Java : 개인과제(키오스크), 프로그래머스 문풀) (0) | 2023.05.30 |
|---|---|
| 2023-05-27 TIL (git 소스트리 활용하기) (1) | 2023.05.27 |
| 2023-05-25 TIL (Java 문법 학습, 프로그래머스 문풀) (0) | 2023.05.25 |
| 2023-05-24 TIL (Java, 프로그래머스 문제풀이) (1) | 2023.05.24 |
| 2023-05-23 TIL (Java : Collections Framework, 프로그래머스 문풀) (0) | 2023.05.23 |