Java 에서 문자열을 처리하는 대표적인 클래스로
String
,StirngBuffer
,StringBuilder
가 있습니다.
세 방식의 가장 큰 차이는 String 클래스는 Immmutable : 불변
하고 StirngBuffer, StringBuilder는 mutable : 변함
한다는 점입니다.
여기서 변한다는 것의 의미는 문자열 객체가 생성되었을 때 할당된 메모리 공간이 변하는 것에 대한 유무 입니다.
String
은 객체가 생성되면 Heap 메모리 영역의 String Constant Pool 내부에 저장됩니다. 만약 생성된 String 객체에 변화가 생긴다면 Immutable Class이기 때문에 기존의 메모리 공간 내의 값이 변하는 것이 아니라 새로운 String 객체를 생성하여 변경된 문자열을 나타냅니다. 기존 메모리 영역은 Garbage로 남아있다가 Garbage Colloection
에 의해 사라지게 됩니다.
String str = "Back";
str += "-End";
이러한 Immutable Class 인 String
은 장점 :
불변이기 때문에 객체에 대한 신뢰도가 높고 조회가 많은 환경이나 멀티 스레드에서 동기화 없이 객체를 공유할 수 있습니다.
하지만 단점 :
문자열에 대한 연산이 잦은 환경에서는 힙 메모리에 많은 Garbage가 생성되어 어플리케이션 성능을 저하 시킬 수 있습니다.
따라서 잦은 연산을 수행하는 환경에서는 Mutable Class인 StringBuffer / StringBuilder
을 사용하는 것이 유리합니다.
두 클래스는 내부 Buffer(동적 배열)에 문자열을 저장해 두고 그 안에서 데이터를 변경하는 구조로 되어 있으므로 새로운 메모리 영역의 추가 없이 기존 Buffer의 크기를 늘리며 빠르고 유연하게 문자열을 조작 가능합니다.
기본적으로 StringBuffer 와 StringBuilder
는 동일한 API를 갖습니다. 먼저 두 Class에서 지원하는 Method 를 정리해 보겠습니다.
Method
StringBuilder str = new StringBuilder("HW");
// StringBuffer str = new StringBuffer("HW");
System.out.println(str); // HW
str.append(123);
str.append("BYE").append(456); //연이어서 사용 가능
// HW123BYE456
str.delete(2, 5); // HWBYE456
str.insert(2, 789); // HW789BYE456
str.replace(5, 8, "WELCOME"); // HW789WELCOME456
System.out.println(str.substring(5)); // WELCOME456
str.reverse(); // 654EMOCLEW987WH
그렇다면 둘의 차이점은 무엇일까요?
바로 동기화(Synchronized) 여부입니다. StringBuffer
는 각 Method 별로 동기화 키워드를 지원하여 멀티쓰레드 환경에서 안전성을 보장합니다. 반면, StringBuilder
은 동기화를 보장하지 않습니다.
(위에서 소개했듯이 String
Class도 Immutable 하기에 멀티쓰레드 환경에서 안전성을 보장합니다.)
다음의 Append Method 구현을 통해 동기화 여부를 확인해 보았습니다.
@Override
@IntrinsicCandidate
public StringBuilder append(String str) {
super.append(str);
return this;
}
@Override
@IntrinsicCandidate
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
하지만 단일쓰레드 환경에서는 동기화 처리 과정이 없는 StringBuilder
가 더 좋은 성능을 보입니다.
정리하자면, 일반적으로는 각각 다음과 같은 경우에 사용하는 것이 유리하다 할 수 있습니다.
String
: 문자열 연산이 적거나 단일스레드 환경
StringBuffer
: 문자열 연산이 많거나 멀티쓰레드 환경일 경우
StringBuilder
: 문자열 연산이 많거나 단일쓰레드 또는 동기화를 고려하지 않아도 되는 환경