코딩테스트에 도움되는 StringBuilder
, BufferedReader
, BufferedWriter
에 대해 알아보자.
특히 높은 레벨의 코딩테스트에서는 실행시간이나 메모리 사용량 등의 제약조건이 있기때문에 익혀두면 좋다.
내가 느끼기엔 낮은 레벨의 문제에서도 성능을 신경 쓰면 점수도 조금 더 주는 것 같다. (착각일지도 모름 ㅎ.ㅎ)
String vs StringBuilder
String
(불변 객체)String
객체는 불변(immutable)이기 때문에 한 번 생성된 문자열은 바꿀 수 없다. 즉, 문자열을 수정할 때마다 새로운 String 객체가 만들어지므로 메모리를 많이 차지하고 속도도 느려질 수 있다.
String str = "Hello";
str += " World";
str += "!";
System.out.println(str);
위 코드에서 str
이 변하는 것처럼 보이지만, 실제로는 "Hello"
, "Hello World"
, "Hello World!"
세 개의 String
객체가 메모리에 존재하게 되어 비효율적이다.
기존 문자열은 GC(가비지 컬렉션)에 의해 나중에 정리된다.
StringBuilder
(가변 객체)반면, StringBuilder
는 내부 버퍼를 사용하여 기존 문자열을 직접 수정하므로 속도가 훨씬 빠르다.
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
sb.append("!");
System.out.println(sb.toString());
여기서 새로운 객체를 생성하는 것이 아니라, 기존의 StringBuilder
내부 버퍼를 수정하므로 String
보다 성능이 우수하다.
💡 언제 StringBuilder를 사용할까?
append
, insert
, replace
등)for
, while
에서 +=
대신 사용)StringBuffer
보다 빠른 연산이 필요하고, 멀티스레드 환경이 아닐 때(⭐+추가) StringBuffer vs StringBuilder
String | StringBuffer | StringBuilder | |
---|---|---|---|
속성 | 불변(Immutable) | 가변(Mutable) | 가변(Mutable) |
성능 | 느림 | 중간 (멀티스레드 안전) | 가장 빠름 (단일 스레드) |
스레드 안전성 | ❌ | ✔️ (멀티스레드 지원) | ❌ |
동기화 | 불필요 | 있음 | 없음 |
StringBuffer
는 StringBuilder
와 거의 비슷한 역할을 한다. String
처럼 불변이 아니라 기존 문자열을 수정하는 방식이라서 String
보다 빠른 성능이라는 것은 동일하다.
차이점은 StringBuffer
는 synchronized(동기화)
가 되어 있고, StringBuilder
는 그렇지 않다는 점이다.
즉, StringBuilder
는 성능이 더 빠르기때문에 싱글 스레드에서 사용하는 게 좋고, StringBuffer
는 멀티스레드 환경에서 데이터가 꼬이지 않도록 동기화가 필요할 때 사용하는 게 좋다.
Scanner vs BufferedReader
코딩 테스트에서는 입력 속도도 중요한 요소다.
문제를 풀다 보면 입력 속도가 성능에 큰 영향을 미치는 경우가 많다.
Scanner
(편리한 입력)Scanner
는 다양한 데이터 타입을 쉽게 읽을 수 있고, 정규 표현식까지 활용할 수 있어 편리하다
Scanner sc = new Scanner(System.in);
int num = sc.nextInt(); // 정수 입력
String str = sc.next(); // 문자열 입력
sc.close();
그러나, Scanner
는 내부적으로 입력을 한 글자씩 읽고 변환하는 과정이 많아서 속도가 느리다.
BufferedReader
(빠른 입력)대량의 입력을 처리할 때는 BufferedReader
를 사용하면 속도가 훨씬 빠르다.
보통 System.in
과 함께 사용하려면 InputStreamReader
와 함께 사용한다.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine(); // 한 줄 입력
int num = Integer.parseInt(br.readLine()); // 문자열 → 숫자로 변환
br.close();
BufferedReader
는 입력을 한 번에 버퍼에 저장한 후 처리하므로 Scanner보다 빠르다.
다만, 숫자 입력을 받으려면 Integer.parseInt(br.readLine())
처럼 명시적으로 변환해야 하는 번거로움이 있다.
💡 언제 Scanner를 사용할까?
int
, double
, String
)을 쉽게 처리할 때💡 언제 BufferedReader를 사용할까?
System.out.println() vs BufferedWriter
출력도 입력과 마찬가지로 성능 차이가 난다.
System.out.println()
(편리한 출력)System.out.println("Hello, World!");
System.out.println(100);
System.out.println(3.14);
이렇게 간단한 코드에선 문제가 없지만, 반복문에서 자주 사용하면 비효율적이다.
이유는 매번 System.out
에 데이터를 직접 보내기 때문이다.
BufferedWriter
(빠른 출력)BufferedWriter
는 데이터를 버퍼에 모아서 한 번에 출력하므로 성능이 향상된다.
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bw.write("Hello, World!\n");
bw.write("BufferedWriter는 빠르다.\n");
bw.flush(); // 출력 후 반드시 flush() 필요
bw.close(); // 자원 해제
버퍼를 이용하면 여러 번 write()
를 호출해도 실제 I/O 연산을 줄여서 성능을 개선할 수 있다.
💡 언제 System.out.println()을 사용할까?
💡 언제 BufferedWriter를 사용할까?
BufferedWriter
는 FileWriter
와 함께 쓰면 더욱 효율적)기능 | String | StringBuilder | BufferedReader | Scanner | BufferedWriter | System.out.println() |
---|---|---|---|---|---|---|
가변성 | 불변 | 가변 | - | - | - | - |
속도 | 느림 | 빠름 | 빠름 | 느림 | 빠름 | 느림 |
멀티스레드 지원 | ✔️ | ❌ (StringBuffer 사용 시 ✔️) | - | - | - | - |
입출력 최적화 | - | - | ✔️ | ❌ | ✔️ | ❌ |
사용 예시 | 문자열 변경 없음 | 문자열 반복 수정 | 빠른 입력 필요 | 간단한 입력 | 빠른 출력 필요 | 간단한 출력 |
1. 문자열 다루기
StringBuilder
가 String
보다 성능이 좋음. 2. 입력 속도 비교
BufferedReader
가 Scanner
보다 빠름. Scanner
는 간편하지만 속도가 느림. 3. 출력 속도 비교
BufferedWriter
가 System.out.println()
보다 빠름. BufferedWriter
를 쓰고, 적다면 System.out.println()
을 사용. 코딩 테스트에서 입출력 속도는 중요하다.
원시적인 풀이 방법에서 벗어나서 이것들을 사용하는 습관을 들여야겠다.