본문 바로가기
Web Technologies 🖥️/java

BufferedWriter 는 뭔데 sysout 보다 빨라? - JAVA

by dudefromkorea 2023. 12. 8.

자바를 입문하게 된다면

System.out.println("Hello World");

맨 처음 접하게 된다

 

그렇게 우리는 자연스럽게

Scanner 와 sysout 으로 입 / 출력을 관리하게 된다

 

하지만

알고리즘 풀이나 기타 상황에서

성능적인 코드를 작성해야 할 때

 

더 빠른 함수가 있다면?

고려해보지 않을 이유가 없다

 

 

BufferedReader & BufferedWriter

java.io 에 속한 이 녀석들이

바로 그에 대한 해결책이다

그 이유를 살펴보자

 

<더 빠른 이유>

BufferedWriter 의 경우

데이터를 내부 버퍼에 저장하고

버퍼가 가득 차면 한 번에 데이터를 출력하나

 

sysout 의 경우 호출될 때마다 즉시 출력하므로

반복적인 I / O 작업으로 성능이 저하된다

 

이러한 특성 때문에 I / O 작업의 횟수에서

성능차이가 발생하는 것이고

쉽게 말해 버퍼링 때문이라고 할 수 있겠다

 

여기서 드는 의문점은

"그렇다면 소량의 데이터를 다룬다면?"

 

애초에 소량의 데이터를 다루면서

성능적인 측면을 고려한다는 게

말이 모순인 거 같아 해당 의문은 바로 해결

 

하지만 굳이 따져보자면 소량의 데이터일 경우

버퍼링 기능은 큰 성능 이점을 제공하지 않을 수 있기에

sysout 이 더 빠르게 작동할 가능성이 크다

 

그러나!!

무조건으로 빠르다고 해서

 하나를 고집하며 사용하는 것은 바람직하지 않다

 

각각의 특성들과 장 / 단점을 고려하여

상황에 맞게 사용할 수 있도록 하자

 

<BufferedReader vs Scanner>

<경계 인식>

Scanner 는 Space 와 Enter

모두 경계로 인식하지만

 

BufferedReader 는 Enter 만 경계로 인식하기 때문에

Space 가 들어가는 경우 별도로 데이터를 가공하는 작업이 추가된다

 

<데이터 타입>

다양한 데이터를 허용하는 Scanner 와는 다르게,

(next(), nextInt(), nextLine(), nextDouble(), etc...)

 

BufferedReader 의 경우

read() 를 통해 받은 문자를 항상 int 로 반환하고

(char 를 ASCII 값으로 반환)

 readLine() 을 통해 받은 문자열을 항상 String 으로 반환한다

또한 이 과정에서 IOException 이 발생하므로 예외를 명시적으로 처리해야 한다

 

<BufferedReader.readLine() vs Scanner.nextLine()>

BufferedReader.readLine()

현재 줄의 내용을 읽고 줄 바꿈 문자를

포함하지 않은 채로 줄의 끝에서 멈추나

 

Scanner.nextLine()

줄 바꿈 문자까지 포함한 채로 읽은 뒤

줄 바꿈 문자를 제외한 나머지를 반환한다

 

 

<BufferedWriter vs sysout>

<길어지는 코드...>

BufferedWriter 의 경우에는 버퍼를 잡아놓았기 때문에

반드시 flush() 와 close() 를 통해 버퍼를 닫아줘야 한다

마찬가지로 예외처리가 필수적이다

 

 

결론지어보자면

BufferedReader 와 BufferedWriter

파일 처리나 네트워크 통신 등에서

대량의 데이터를 읽는 데 적합하고

 

Scanner 와 sysout 은 

사용자로부터 입력 처리를 받고

콘솔에 로그나 간단한 출력에 적합하다

 

 

코드를 살펴보자

입력값은 Hello World 이고,

가독성을 위해 입력값은 " " 처리

BufferedReader / BufferedWriter Demo

public class BufferedDemo {
	public static void main(String[] args) throws IOException { // 예외처리 필수

		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));

		bufferedWriter.write("문자열을 입력하세요: ");
		
		if (bufferedWriter != null) {
			bufferedWriter.flush(); // 출력하면서 버퍼 비워주기
		}

		bufferedWriter.write(bufferedReader.readLine());
		
		if (bufferedWriter != null) {
			bufferedWriter.flush(); // 출력하기 위해 필수
			bufferedWriter.close(); // flush()가 포함되어 있긴 함
		}

	}
}
/*
 * <출력 결과>
 * 문자열을 입력하세요: "Hello World"
 * Hello World
 */

 

만약

중간에 write 한 문구를 flush 해주지 않는다면?

BufferedReader / BufferedWriter Demo without flush

public class BufferedDemoWithoutFlush {
	public static void main(String[] args) throws IOException { 

		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));

		bufferedWriter.write("문자열을 입력하세요: ");
		
		/*if (bufferedWriter != null) {
			bufferedWriter.flush(); 
		}*/

		bufferedWriter.write(bufferedReader.readLine());
		
		if (bufferedWriter != null) {
			bufferedWriter.flush(); 
			bufferedWriter.close(); 
		}

	}
}
/*
 * <출력 결과>
 * "Hello World"
 * 문자열을 입력하세요: Hello World
 */

 

 

차이점이 명확하다

 적절한 시기에 flush() 해주지 않을 경우

출력이 안될뿐더러, 버퍼에 남아있다가

추후에 flush() 할 때에 출력된다

 

 

마지막으로

숫자를 입력받는 예시 코드를 살펴보자

BufferedReader / BufferedWriter Demo with int

public class BufferedDemoInt {
	public static void main(String[] args) throws IOException {

		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));

		bufferedWriter.write("숫자를 입력하세요: ");

		if (bufferedWriter != null) {
			bufferedWriter.flush();
		}

		int number = Integer.parseInt(bufferedReader.readLine());

		// bufferedWriter.write(number);
		// bufferedWriter.write("+ 로 자동변환하기 =>" + number);
		bufferedWriter.write(String.valueOf(number));
		if (bufferedWriter != null) {
			bufferedWriter.flush();
			bufferedWriter.close();
		}

	}
}
/*
 * <출력결과>
 * 숫자를 입력하세요: "123"
 * 123
 */

 

 

만약 주석처리 된

" bufferedWriter.write(number); " 를 사용한다면?

 

write 메소드는 들어온 정수 값의 해당하는 ASCII 값을 출력하는 역할인데

단일 정수가 아닌 " 123 " 이 들어왔기 때문에 에러가 발생할 것이다

 

대체제로는 다른 문자열과 혼합하여 " + " 기호를

사용하면 숫자를 문자열로 자동 변환하여 출력을 해준다

728x90
반응형