자바에서는 대표적으로 문자열을 다루는 자료형 클래스로
String,StringBuffer,StringBuilder가 있다. 세가지 클래스 모두 문자열을 다루는데 사용되지만 사용 목적에 따라 쓰임새가 다르다.
그렇다면 왜 이렇게 굳이 여러 클래스를 만들어 놓은건지, 그 차이점과 특징에 대해 알아보도록 하자.
StringBuffer / StringBuilder 클래스는 문자열을 연산(추가하거나 변경)할 때 주로 사용하는 자료형이다.
물론 String 자료형으로도 +, concat()을 이용하여 문자열을 이어붙일 수 있지만, 아래에서 설명할 불변 자료형인String의 특성상 문자열을 이어붙일 때마다 매번 내용이 합쳐진 새로운 String 인스턴스를 생성하게 된다. 따라서 String은 문자열의 결합이 많아질수록 공간이 낭비되고 속도 또한 느려지게 된다.
String result = "";
result += "hello";
result += " ";
result += "jump to java";
System.out.println(result); // hello jump to java
// → 문자열이 합쳐질때마다 새로운 인스턴스 생성
그래서 자바에서는 문자열 연산을 전용으로 하는 StringBuffer/StringBuilder 클래스가 존재한다. StringBuffer 클래스는 내부적으로 buffer(데이터를 임시로 저장하는 메모리)라고 하는 독립적인 공간을 가지게 되어 문자열을 바로 추가할 수 있어 공간의 낭비도 없으며 문자열 연산 속도도 매우 빠르다는 특징이 있다.
StringBuffer sb = new StringBuffer(); // StringBuffer 객체 sb 생성
sb.append("hello");
sb.append(" ");
sb.append("jump to java");
String result = sb.toString();
System.out.println(result); // hello jump to java
// → + 연산보다는 복잡해 보이지만 연산 속도가 빠름
StringBuffer와 비슷한 자료형으로StringBuilder가 있는데, StringBuilder 사용법은 StringBuffer와 동일하다. StringBuffer와 StringBuilder의 차이는 뒤에서 다뤄보겠다.
String str = "abcdefg";
StringBuffer sb = new StringBuffer(str); // String -> StringBuffer
System.out.println("처음 상태 : " + sb); // 처음상태 : abcdefg
System.out.println("문자열 String 변환 : " + sb.toString()); // StringBuffer를 String으로 변환하기
System.out.println("문자열 추출 : " + sb.substring(2,4)); // 문자열 추출하기
System.out.println("문자열 추가 : " + sb.insert(2,"추가")); // 문자열 추가하기
System.out.println("문자열 삭제 : " + sb.delete(2,4)); // 문자열 삭제하기
System.out.println("문자열 연결 : " + sb.append("hijk")); // 문자열 붙이기
System.out.println("문자열의 길이 : " + sb.length()); // 문자열의 길이구하기
System.out.println("용량의 크기 : " + sb.capacity()); // 용량의 크기 구하기
System.out.println("문자열 역순 변경 : " + sb.reverse()); // 문자열 뒤집기
System.out.println("마지막 상태 : " + sb); // 마지막상태 : kjihgfedcba
StringBuilder 클래스의 메서드 사용법과 동일하다.String과 StringBuffer / StringBuilder의 큰 차이점은 가변자료형이냐, 불변자료형이냐이다.
기본적으로 자바에서는 String 객체의 값을 변경할 수 없다.
이는 한번 할당된 공간이 변하지 않는다고해서 불변(immutable) 자료형이라고 한다.
아래 예제를 보면, 단순히 변수 str이 참조하는 값에 World 문자열을 더해서 str 변수를 업데이트 시킨것으로 볼 수 있는데, 실제 메모리에서는 hello world값을 저장할 영역을 따로 만들고 변수 str을 다시 참조하는 식으로 동작한다.
String str = "hello";
str = str + " world";
System.out.println(str); // hello world

이러한 이유로 String 객체는 문자열 연산이 많은 경우 성능이 좋지 않다.
하지만 불변 객체는 간단하게 사용가능하고, 동기화에 대해 신경쓰지 않아도 되기때문에(Thread-safe), 내부 데이터를 자유롭게 공유 가능하다.
StringBuffer나 StringBuilder의 경우 문자열 데이터를 다룬다는 점에서 String 객체와 같지만, 객체의 공간이 부족해지는 경우 버퍼의 크기를 유연하게 늘려주어 가변(mutable)적이라는 차이점이 있다.
두 클래스는 내부 buffer에 문자열을 저장해두고 그 안에서 추가,수정,삭제 작업을 할 수 있도록 설계되어 있다.
String 객체는 한번 생성되면 불변적인 특징 때문에 값을 업데이트할때마다 새로운 문자열을 가진 인스턴스가 생성되어 메모리 공간을 차지하지만 StringBuffer / StringBuilder는 가변성을 가지기 때문에 동일 객체 내에서 문자열 크기를 변경하는 것이 가능하다.

따라서, 문자열의 추가, 수정, 삭제가 빈번하게 발생할 경우라면 String이 아닌 StringBuffer / StringBuilder을 사용하는 것이 좋다.
StringBuffer / StringBuilder 둘다 가변 자료형이며, 내부 buffer를 사용해서 문자열 작업을 하고, 사용법도 거의 비슷하다. 그렇다면 둘의 차이는 뭘까?
바로 멀티스레드에서 안전하냐, 안전하지않느냐의 차이 딱 한가지다.
결과를 바로 말하자면,
StringBuffer는 각 메서드 별로 동기화를 지원하여 멀티스레드 환경에서도 안전하게 동작하며, StringBuilder는 동기화를 지원하지 않는다.
그렇기 때문에 멀티스레드 환경이라면 값 동기화 보장을 위해 StringBuffer를 사용하고, 단일 스레드 환경이라면 StringBuilder를 사용하는 것을 권장한다.
단순히 성능만 놓고 본다면 연산이 많은 경우 StringBuilder > StringBuffer >>> String
| 차이점 | String | StringBuffer | StringBuilder |
|---|---|---|---|
| 선언 방식 | String str = "Hello"; |
StringBuffer sb = new StringBuffer("Hello"); |
StringBuilder sb = new StringBuilder("Hello"); |
| 문자열 변경 방법 | str += " World"; |
sb.append(" World"); |
sb.append(" World"); |
| 클래스 종류 | 불변(immutable)한 클래스 | 가변(mutable)한 클래스 | 가변(mutable)한 클래스 |
| 변수의 추가 및 변경 시 메모리 성능 | 불리함 | 유리함 | 유리함 |
| 단일 쓰레드 환경에서 성능 | 안정적 | 안정적 | 안정적 |
| 멀티 쓰레드 환경에서 성능 | 안정적 | 안정적, 동기화 과정에서 성능 저하 | 안정적, 동기화 과정에서 성능 저하 X |
| 속도 | 매우 느림 | 빠름 | 빠름 |
| 사용 목적 | 문자열 추가와 변경이 발생하지 않는 경우 사용하는 것이 좋다. | 멀티쓰레드 환경에서 문자열의 변수의 추가와 변경이 자주 발생하는 경우 사용하면 좋다. | 단일쓰레드 환경에서 문자열의 변수의 추가와 변경이 자주 발생하는 경우 사용하면 좋다. |
Java에서 문자열을 다룰 때 사용하는 String, StringBuilder, StringBuffer는 각각 특징이 다릅니다.
String은 불변 객체라 한번 생성되면 변경할 수 없습니다. 따라서 문자열을 더하거나 수정할 때마다 새로운 객체가 생성되어 메모리와 성능상 비용이 발생합니다. 변경이 거의 없는 상수나 리터럴을 다룰 때 적합합니다.
StringBuilder, StringBuffer는 가변 객체라 내부 buffer에서 문자열 작업을 효율적으로 진행할 수 있습니다. 두 클래스의 차이점은 동기화 여부입니다.
StringBuilder는 동기화를 지원하지 않아 멀티스레드 환경에서 안전하지 않지만, 단일 스레드 환경에서는 가장 빠릅니다.
StringBuffer는 각 메서드별로 동기화를 지원하여 멀티스레드 환경에서 안전하게 사용할 수 있습니다.