본문 바로가기

JAVA

JAVA String, StringBuilder, StringBuffer 의 차이점

자바를 공부하다보면 String, StringBuilder, StringBuffer 이 세가지 클래스를 한 번씩은 본 적이 있을 것이다.

 

셋 다 문자열을 다루고 있는 것 같고, 별 차이 없어보이는데 무슨 차별점으로 3개가 존재하는 것인지에 대해 찾아보았는데 꽤 유용한 정보를 얻은 것 같다.

 

3개 서로 간의 차이점을 포스트해보겠음.

 

1. String

문자열을 사용할 때 가장 많이, 보편적으로 이용되는 클래스다.

String str = new String("example");

위와 같이 쓰기도 하고, 리터럴 문자열로 바로 대입해버릴 수도 있다.

 

제일 많이 쓰는 클래스인 만큼, 빠르고 쉽게 문자열을 할당하고 사용할 수 있다는 점이 장점이다.

 

하지만 이런 string 클래스에도 단점이 존재하는데, 문자열에 변화를 줄 때 시간 소모가 너무 많이 든다는 것이다.

String str = "";
for(int i=0;i<1000000;i++){
	str += "a";
}

System.out.println(str);

예를 들어 위와 같은 예시가 있다고 하면, 답은 당연히 aaaa... 일텐데, "+=" 부분, 그러니까 concatenation의 작업은 메모리 초기화와 생성을 이루며 진행되기 때문에 concatenation이 많거나 loop 내에 있으면 string의 사용은 부적합하다.

 

자세히 설명해보면, str += "a" 부분은 str 뒤에 a를 붙이는게 아니라 str 뒤에 a를 붙인 new String을 할당하는 것이다.

 

이는 String이 immutable(불변적)이기 때문이다.

 

변하지 않는 특성을 가지기 때문에 변화를 줄 때 새로운 String을 생성하는 수 밖에 없는 것임.

 

concatenation 연산이 16만번 이상이 되면 실행 시간이 10초가 넘어간다고 하니, 해당 연산이 많을 경우엔 사용하지 않는 것이 좋다. (위 코드 실행 시간은 1분 ㄷㄷ)

 

다만, StringBuffer나 StringBuilder와는 달리 불변성을 가지므로 멀티쓰레드에서 synchronization을 신경쓸 필요가 없다. (thread-safe의 특성을 가짐)

 

즉, 문자열 데이터 조회 수가 많거나 멀티 쓰레드에서 사용할 때 타 클래스에 비해 속도가 더 빠르다.

 

+JDK 1.5 이상에서는 String에서 concatenation 연산을 사용하면 StringBuilder로 컴파일되게 해놓았다고 하지만, 그래도 적절히 구별하여 사용할 줄 알아야 함

 

2. StringBuffer + StringBuilder

위의 immutable한 String과는 다르게 StringBuffer와 StringBuilder는 가변적(mutable)이다.

 

StringBuffer와 StringBuilder 모두 문자열에 변화를 주면 해당 문자열에서 변경시킬 수 있다.

StringBuilder builder = new StringBuilder("");
for(int i=0;i<1000000;i++){
	builder.append("a");
}

System.out.println(builder.toString());

위와 같이 사용하면 되고, StringBuffer도 비슷하게 사용하면 된다.

 

String과는 다르게 append시 "a"가 붙은 새로운 문자열을 생성하는 것이 아니라 그 자체의 문자열에 "a"를 붙이는 것이므로 String에 비해서 메모리 파기와 생성에 드는 시간이 단축된다.

 

문자열 변경이 많을 때 위 2개의 클래스 중 하나를 선택하여 사용하면 String보다 훨씬 빠른 성능을 보인다.

 

3. StringBuffer vs StringBuilder

두 클래스는 모두 mutable(가변적) 특성을 가지고 있다.

 

비슷해 보이는 이 두 클래스에도 차이점이 있는데, 바로 thread-safe 지원 여부다.

 

StringBuffer는 String과 같이 thread-safe의 특성을 가진다.

 

즉, 멀티쓰레드 환경에서 사용하기 적합하다.

 

반대로, StringBuilder는 지원되지 않으므로 멀티쓰레드에 쓰기엔 좋지 않다.

 

대신 StringBuilder는 멀티쓰레드가 아닌 환경에서 StringBuffer보다 빠른 성능을 보인다.

 

정리하자면 다음과 같다.

 

  변화 특성 Thread-Safe 지원 여부
String immutable(불변적) O
StringBuffer mutable(가변적) O
StringBuilder mutable(가변적) X

 

 

4. String vs StringBuffer vs StringBuilder 속도 비교

실제로 내가 실험한 것은 아니고, 어느 포스팅에서 가져온 것이다. (맨 아래 링크 참조)

 

설명을 해보자면, 비어있는 문자열에 "a"를 계속 추가하여 걸린 시간을 나타낸 것이다.

 

x축이 추가한 횟수, y축이 걸린 시간이다.

 

String은 concatenate할 수록 새로 만드는 문자열의 길이가 길어지니 지수함수를 그린다고 볼 수 있겠다.

 

StringBuffer와 StringBuilder 또한 그렇기에 수가 커질 수록 지수함수를 그리는 것 같다.

 

다만 이해가 안되는 건 StringBuffer와 StringBuilder 모두 횟수 10만 이하 일 때 실행시간이 내려가는 시점이 있다는 것인데, 이유는 아직 잘 모르겠다.

 

5. 추가 내용

JAVA에서 속도 실험 결과를 시각화하는 프로그램을 만들어 직접 실험해보았다.

 

실험 조건은 위와 같다.

 

5-1. StringBuilder에서 a라는 문자를 append하는 것을 N회 반복 시 나타나는 실행 시간 그래프

주황은 "a"로 append, 파랑은 'a'로 append 한 것.

5-2. StringBuffer와 StringBuilder의 append() 실행시간 비교

위의 타 블로그의 결과와 별 차이가 없음

5-3. String과 StringBuilder에서의 append() 실행시간 차이

append() 6만회 반복 시 실행 시간 5900배 차이가 난다.

5-4. String의 append() 실행시간 그래프

10만번 반복 실행 시 대략 1.4초 소요

(...) 앞으로 append()는 StringBuffer나 StringBuilder를 통해서 하도록 하자.

 

 

참고한 링크

https://jeong-pro.tistory.com/85

http://egloos.zum.com/deblan2/v/419830 (속도 실험)