코딩 테스트 문제를 풀어보기 위해 Beakjoon Online Judge에서 기초부터 문제를 풀고 있는데 15552번 "빠른 A+B" 문제에서 BufferedReader, Writer에 대해 알게 되었다. 아마 대학에서 배웠을 테지만 쓰지 않다 보니 잊은 것 같다.
1. Buffer
BufferedReader와 BufferedWriter는 버퍼를 이용해서 읽고 쓰는 클래스로, 버퍼를 사용하기 이용하기 때문에 이 함수를 이용하면 입출력의 효율이 좋아진다.
키보드나 모니터와 같은 외부 장치와의 데이터 입출력은 CPU의 성능 차이가 크기 때문에 버퍼를 두고 모아두었다 한 번에 전송하는 것이 효율적이다.
2. BufferedReader
BufferedReader는 개행 문자를 경계로 인식하고 받은 데이터가 String으로 고정되기 때문에 데이터를 따로 가공해야 하는 번거로움이 있지만 Scanner에 비해 빠르다는 장점이 있다.
10,000,000개의 0~1023 범위의 정수를 한 줄씩 읽고 입력으로 받은 정수의 합을 출력하는 프로그램을 구현할 때 BufferedReader와 Scanner의 차이는 밑의 표와 같다. [1]
입력방식 | 수행 시간(초) |
---|---|
java.util.Scanner | 6.068 |
java.io.BufferedReader | 0.934 |
BufferedReader 사용법
BufferedReader의 readLine()을 사용하면 데이터를 한 줄씩 읽을 수 있다. readLine()의 반환 값은 String이기 때문에 다른 타입으로 사용하려면 형 변환을 필수로 해주어야 한다.
import java.io.*;
class BufferedReaderEx {
public static void main(String[] args) {
try { // BufferedReader를 사용할 경우 예외처리 혹은 throws IOException을 해주어야 한다.
// 콘솔에서 입력을 받는 경우
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 파일에서 입력을 받는 경우
FileReader fr = new FileReader("파일명");
BufferedReader br_f = new BufferedReader(fr);
int num = Integer.parseInt(br.readLine());
br.close(); // 입출력이 모두 끝나면 닫아주어야 한다.
String line = "";
for (int i = 1; (line = br_f.readLine()) != null; i++) {
System.out.println(line);
}
} catch(IOException e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
한 줄씩 읽어오는 것이 아닌 공백 단위로 끊어줄 때는 StringTokenizer의 nextToken()을 이요하거나 String의 split()을 이용하면 된다.
BufferedReader의 메소드들
Modifier and Type | Method and Description |
---|---|
void | close() 입력 스트림을 닫고 사용하던 자원들을 해제한다. |
void | mark(int, readAheadLimit) 스트림의 현재 위치를 마킹한다. |
boolean | markSupported() 스트림이 mark 기능을 지원하는지 boolean으로 알려준다. |
int | read() 한 글자만 읽어 아스키코드 값으로 반환한다. |
int | read(char[] cbuf, int offset, int length) cbuf의 offset위치부터 length의 길이만큼 문자를 스트림으로부터 읽어온다. |
String | readLine() 한 줄을 읽어온다. |
boolean | ready() 입력 스트림이 사용할 준비가 되어있는지 알려준다. |
void | reset() 읽는 위치를 처음으로 변경한다. 마킹이 되어있을 경우 마킹된 위치로 변경된다. |
long | skip(long n) n개의 문자를 건너뛴다. |
3. BufferedWriter
System.out.print()와 동일한 기능을 하는 클래스로 버퍼를 이용하기 때문에 속도가 빠르다. System.out.println()처럼 개행을 동시에 해주지 않기 때문에 개행을 하면 write에 "\n"을 넣어주거나 newLine()을 사용해야 한다.
BufferedWriter 사용법
import java.io.*
class BufferedWriterEx {
public static void main(String[] args) {
BufferedWriter bw = new BufferedWriter(new FileWriter("파일명"));
bw.write("출력할 내용 \n");
bw.newLine(); // 개행
bw.flush(); // 남은 데이터 모두 출력
bw.close(); // 스트림 닫기
}
}
BufferedWriter를 사용 후 닫기 전에 flush()를 이용하여 버퍼를 비워주어야 한다.
BufferedWriter의 메소드들
Modifier and Type | Method and Description |
---|---|
void | close() 스트림을 닫는다. |
void | flush() 스트림을 비운다. |
void | newLine() 개행 문자를 출력한다. |
void | write(char[] cbuf, int offset, int length) 버퍼 offset위치부터 length크기만큼 출력한다. |
void | write(int c) 한 글자를 출력한다. |
void | write(String s, int offset, int length) 문자열에서 offset부터 length만큼 출력한다. |
※ String, StringBuffer, StringBuilder
-
String : String은 리터럴을 통해 생성되면 그 인스턴스의 메모리 공간은 절대 변하지 않는다. '+' 연산이나 concat()을 이용해 문자열 값에 변화를 줘도 메모리 공간 내의 값이 변하는 것이 아니라 "String Pool"이라는 공간 안에 메모리를 할당 받아 새로운 String 클래스 객체를 만들어 문자열을 나타내는 것이다.
- String 클래스는 문자열 연산이 적고, 자주 참조(조회)하는 경우에 사용하면 좋다. (특히 멀티 스레드 환경에서 신경 쓸 것이 없어서 좋다.)
-
StringBuffer, StringBuilder : String과 다르게 변경이 가능하므로 한 번만 만들고 메모리의 값을 변경시켜서 문자열을 변경한다. StringBuffer와 StringBuilder의 차이는 StringBuffer는 멀티 스레드 환경에서 synchronized 키워드를 이용해 동기화가 가능하다. 즉, thread-safe히다. 반대로 StringBuilder는 thread-safe하지 않다. 대신 싱글 스레드 환경에서는 StringBuilder가 연산처리가 빠른 장점이 있다.
- StringBuffer와 StringBuilder는 문자열 연산이 많을 때 사용하면 좋고 멀티 스레드 환경에서는 StringBuffer, 싱글 스레드 환경이거나 동기화가 필요 없는 경우에는 StringBuilder를 사용하면 좋다.
Reference
'Java' 카테고리의 다른 글
[Java] Maven 라이브러리 Dependency 충돌 해결하기 (0) | 2021.11.04 |
---|---|
[Java] 메서드 참조(Method Reference) (0) | 2021.05.21 |
[Java] javadoc 정리 (0) | 2021.05.04 |
[Java] 와일드 카드가 들어간 IP 검사하기! (0) | 2020.07.13 |
[Java] StringBuffer / StringBuilder (0) | 2020.06.02 |