[Java] StringBuffer vs StringBuilder
String부터 StringBuffer, StringBuilder까지 자바는 문자열을 다루기 위한 3개의 클래스를 제공한다. 개발 초기에는 아무런 생각 없이 String에 값을 계속 더하는 행위를 하지만, 이 방법이 잘못 되었다는 것은 개발이 어느정도 능숙해지고부터이다.
String은 불변적인 객체이다보니 동적으로 문자열이 바뀌는 것에 취약하다. 그래서 새로운 문자열을 더할 경우 기존 문자열을 삭제하고 다시 두개의 문자열을 합친 후 String 변수에 보내는데 이때 garbage collector가 발생하게 된다. 최근의 자바 버전에서는 내부적으로 String에서도 문자열을 합칠 때 강제적으로 StringBuilder로 변하게 되는데 아무튼 적당한 문자열을 String에 하는 것은 큰 문제가 되지 않지만 대용량의 문자열을 String으로 받을 경우 심각한 속도 저하를 느낄 수 있다.
String의 이런 동적인 처리를 대응하기 위해 나온 클래스가 StringBuffer와 StringBuilder이다. StringBuilder는 Java 1.5 버전 이후로 나온 클래스로 StringBuffer보다 빠르다. 그러면 수많은 사람들이 StringBuilder만 쓰면 되지 왜 StringBuffer를 사용하는가하면 다음과 같은 서로간의 장단점이 있기 때문이다.
Thread 접근
StringBuffer의 경우 동기화 되어 있기 때문에 하나의 Thread가 접근을 하였을 때 다른 Thread를 block 할 수 있다. 즉, 데이터의 이상이 없이 안전하게 처리를 할 수 있는 장점이 있다. StringBuilder는 동기화 기능이 없기 때문에 Thread에서 동시에 StringBuilder로 만든 변수에 접근할 경우, 잘못된 처리를 할 수 있는 위험이 있다.
속도
StringBuffer가 StringBuilder보다 동기화라는 기능이 있기 때문에 속도면에서 StringBuilder가 효율적이다.
그럼 StringBuffer와 StringBuilder가 얼마나 속도 차이가 있는지 확인해 보도록 한다.
소스 코드
public class TestMain {
public void testStringBuffer(int loopSize) {
long startTime = System.currentTimeMillis();
StringBuffer sb = new StringBuffer();
for(int i = 0; i < loopSize; i++) {
sb.append("string");
}
System.out.println("string buffer elapsed->"
+ (System.currentTimeMillis()-startTime) + ("ms"));
}
public void testStringBuilder(int loopSize) {
long startTime = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < loopSize; i++) {
sb.append("string");
}
System.out.println("string builder elapsed->"
+ (System.currentTimeMillis()-startTime) + ("ms"));
}
public static void main(String[] args) {
TestMain test = new TestMain();
int loopSize = 10000000;
test.testStringBuffer(loopSize);
test.testStringBuilder(loopSize);
}
}
위 코드는 각각 천만번 loop하여 stringbuffer와 stringbuilder의 append의 성능을 측정하는 코드이다.
실행 결과
string buffer elapsed->332ms
string builder elapsed->156ms
대략 2배 넘게 차이를 보이고 있지만 StringBuffer에 10,000,000 씩이나 루프를 돌려서 데이터를 append하는데 저정도의 속도 차이면 실제 사이트에서도 충분히 양호하며, 오히려 이럴때에는 일관되게 하나의 문자열만 쓰는 것이 유지보수 할때도 편해서 여태까지 StringBuilder를 거의 쓴 적이 없다.
결국 머리아프게 빌더니 버퍼니 고민하지 말고, 그냥 StringBuffer 하나만 쓰고 정말 1ms를 다투는 사이트라면 StringBuilder를 고민해도 될 것 같다. (그러나 그래도 난 StringBuffer를 쓸 것 같지만...)