코드업 기초100제를 풀던중 처음으로 뭔가 난관에 부딛혔다. 바로 1084번 문제인데, 푸는 방법은 정말 간단하다 라고 말하기 조차 민망할 만큼 간단하다. 하지만 나를 곤란에 빠트린건 다름아닌 자꾸 시간초과가 뜬다는 것이다. 구글에 검색을 하여 이 문제를 푼 다른 사람들의 코드를 보면 나와 똑같이 풀었는데, 왜 나는 막히는 걸까??
조금 더 찾아보다가 이런 포스트를 발견했다.
출력속도비교
아마 원인은 내가 입력을 받을 때 사용한 Scanner, 출력을 할때 사용한 System.out.println()이 속도가 많이 느린 탓인것 같다.
따라서 자바 입출력에 관한 내용들을 검색을 통해 공부를 좀 하였고, 빠르게 입출력을 하기위해선 무엇을 써야 하는지 알아보았다.
이것저것 검색을 하다가 문득 궁금한 점이 생겼었다.
자바를 맨처음 배울때 사용한 System.out.println();
이라던가 Scanner를 생성할 때
사용한 new Scanner(System.in)
에서 System 은 도대체 무엇일까??
JAVA의 API문서에서 찾아보면
java.lang.System
public final class System extends Object
The System class contains several useful class fields and methods.
It cannot be instantiated.
Among the facilities provided by the System class are
standard input, standard output, and error output streams;
access to externally defined properties and environment variables;
a means of loading files and libraries;
and a utility method for quickly copying a portion of an array.
위와 같이 적혀 있음을 알 수 있다. 영어는 울렁증이 나기에 다시 한글로 구글형님께 공손히 여쭤보았다.
system 클래스는 표준 입출력을 제공하는 클래스이다.
여기서 표준입출력이란 키보드(표준입력),모니터(표준출력)을 의미한다.
즉 다시말해 키보드를 통해 입력을 받고 이것을 모니터에 출력할 수 있는 도구들을 제공하는 클래스인것.
3가지 멤버변수(필드)가 존재한다.
- in : InputStream타입
- out : PrintStream 타입
- err : out과 동일.
모두 바이트 단위로 입출력을 제공한다.
먼저 입력을 살펴보겠다. Scanner 보다 더 빠른 입력을 하기 위해선
아래와 같이 BufferedReader를 사용한다.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
BufferedReader는 java.io 패키지에 있으므로 사용하기위해선 import를 해주어야 한다.
또한 readLine()
이라는 메서드를 제공하여 Scanner의 nextLine()
처럼 한줄 단위로 읽어 올수 있는데 리턴값이 String이기 때문에 내가 원하는 변수타입으로 직접 변경을 시켜줘야 한다.
출력도 비슷한 이름의 객체를 사용한다. 바로 BufferedWriter 이다.
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bw.write("example\n");
출력은 위 코드에서 보다싶이 write()
메서드를 사용한다. 주의할 점은 System.out의 println()과 달리
개행문자를 따로 쳐주어야 한다. 자동으로 처리를 안해줌.
⚠BufferedReader / BufferedWriter 는 이름에서 알 수 있듯이 버퍼(Buffer)를 가지는 입출력스트림이다.
버퍼란 데이터를 일시적으로 저장하기 위한 공간을 의미한다.
자바에서 입출력스트림들은 운영체제API를 호출하여 입출력장치와 응용프로그램 사이에서 데이터가 전송되도록 하는데 버퍼가 없이 많은 양의 데이터를 입출력 할시에는 그만큼 자주 운영체제 API가 호출되고 또한 그만큼 실행속도가 떨어질 것이다. 어느정도 모아뒀다가 한번에 처리를 하는것이 많은 양을 처리할 땐 더 빠르다는 것이다.
비유를 들자면 물 10리터를 우물에서 퍼와야 하는데 조그만한 양치컵을 들고 수십번 왔다갔다 하는것보단
커다란 약수통 하나 들고가서 몇번 나르는게 더 효율적인 느낌?
BufferedWriter을 사용할 때 주의할 점으로는 flush() 메서드를 사용해주어야 한다는 것이다.
버퍼스트림은 버퍼가 꽉 찼을 때만 출력되는 특징이 있다고 한다. 그러면 프로그램에서 데이터를 출력했지만 버퍼에 들어있어 내 모니터엔 안보일 수 있다는 것.
그리고 BufferedReader와 BufferedWriter 모두 IOException을 발생시킬 수 있으므로
try-catch문을 사용하던, throws를 하던 처리를 해주어야 한다.
아마 백준사이트나 코드업 같은 문제를 풀땐 그냥 throws만 해줘도 문제없을 것 같은 느낌?
잘봤습니다! 감사합니다. 사실 제가 이번주 토요일에 코딩테스트가있는데 혹시 도움을 좀 받을 수있을까요? ㅜㅜ 경험이 전혀없어서요. (코딩테스트 응시 환경하고 제가 준비하고 있는 방향이 맞는 지 확인을 해 주셨으면 좋겠어요!)