Java에서 문자열을 다루는 클래스로는 String, StringBuffer, StringBuilder 가 있다.
연산이 많지 않을 때에는 어떠한 클래스를 사용하더라도 문제가 발생할 가능성은 없지만, 연산 횟수가 많아지거나 멀티스레드, Race Condition 등의 상황이 자주 발생한다면 각 클래스의 특징을 이해하고 상황에 맞는 클래스를 사용하여야 한다.
String
String 객체의 가장 큰 특징은 immutable(불변)이다.
String str = "hello";
str = str + " world";
System.out.println(str); // "hello world"
위 코드를 보면 단지 "hello"가 저장되어 있는 str에 " world"를 붙인 걸로 착각하기 쉽다.
물론 틀린 말은 아니지만 정확히는 메모리에 "hello"와 "hello world" 두 개의 객체가 존재하는 것이다.
String은 불변의 특성을 가지고 있기 때문에 String 클래스의 참조변수 str은 "hello"를 가리키고 있다가 + 연산을 통해 "hello world"라는 값을 새롭게 가리키게 된다. 처음 선언됐던 "hello" 값은 Unreachable 객체가 되어 Garbace Collector에 의해 제거가 된다.
String 클래스는 불변이기 때문에 문자열을 수정하는 시점에 새로운 String 인스턴스가 생성되는 것이다.
변하지 않는 문자열을 자주 읽어 들이는 경우 String 클래스를 사용해 주면 좋은 성능을 기대할 수 있다. 그러나 문자열 추가, 수정, 삭제 등의 연산이 빈번하게 발생하는 경우에 String 클래스를 사용하게 되면 Heap 메모리 영역에 많은 Unreachable 객체가 쌓이게 되어서 메모리 부족 현상이 일어날 수 있고, 애플리케이션 성능에 영향을 끼칠 수가 있다.
StringBuffer / StringBuilder
위와 같은 현상을 해결하기 위해 Java에서는 가변(mutable)적인 StringBuffer / StringBuilder 클래스를 도입했다.
String과는 반대로 가변성의 특징이 있기 때문에 append(), delete() 등의 메서드를 사용하여 동일 객체 내에서 문자열을 변경하는 것이 가능하다. 따라서 문자열의 추가, 수정, 삭제가 빈번하게 일어나는 경우에는 StringBuilder, StringBuffer를 사용하는 것이 좋다.
StringBuilder sb = new StringBuilder("hello");
sb.append(" world");
System.out.println(sb); // hello world
StringBuffer vs StringBuilder
두 클래스의 가장 큰 차이점은 동기화의 유무이다.
StringBuffer는 동기화 키워드를 지원하므로 멀티스레드 환경에서 안전(Thread-safe)하다는 점이 있다.
(String 객체도 불변성의 특징을 가지고 있으므로 마찬가지로 Thread-safe 하다.)
StringBuilder는 동기화를 지원하지 않기 때문에 멀티스레드 환경에서 사용하는 것은 적합하지 않지만, 동기화를 고려하지 않는 만큼 단일스레드 상황에서는 StringBuffer보다 뛰어난 성능을 보여준다.
정리
- String : 문자열 연산이 적고 멀티스레드 환경인 경우
- StringBuffer : 문자열 연산이 많고 멀티스레드 환경인 경우
- StringBuilder : 문자열 연산이 많고 단일스레드 환경이거나 동기화를 고려하지 않아도 되는 경우
참고
'멋진 개발자 > Java & Spring' 카테고리의 다른 글
개발자 성장 기록 51 - MyBatis (0) | 2024.04.18 |
---|---|
개발자 성장 기록 46 - Java의 접근제어자 (0) | 2024.04.12 |
개발자 성장 기록 44 - Concurrent Collection (0) | 2024.04.08 |
개발자 성장 기록 43 - Thread Pool (1) | 2024.04.07 |
개발자 성장 기록 42 - Java 직렬화 (Serialization) (0) | 2024.04.06 |