[Java] String / StringBuilder / StringBuffer의 차이점은 무엇일까?
이번 포스팅에서는 String, StringBuilder, StringBuffer의 특징과 각각의 차이점에 대해 알아보겠습니다.
String
자바에서 String은 불변성을 갖고 있습니다. 즉, 문자열 객체는 최초에 생성되면 절대로 그 값이 변하지 않습니다.
String str = "hello";
str = "hi";
위의 예시에서는 내부적으로 다음과 같이 동작합니다.
즉, 이 상태에서는 "hello"와 "hi" 객체가 힙 영역에 생성되어 있는 상태입니다.
str 변수는 "hello" 객체를 참조하다가 "hi"를 참조하게 됩니다. "hello" 객체는 사라지지 않으며 Heap에 원본 그대로 남아있습니다.
그럼 이 코드는 어떨까요?
String str = "hello";
str = "hello" + " world";
내부적으로는 다음과 같습니다.
기존에 생성되어 있던 "hello" 객체는 그대로 두고 "hello world"라는 새로운 객체가 생성되어 이를 참조하게 됩니다.
각각의 객체들은 고유의 주솟값을 갖기 때문에 문자열 덧셈을 굉장히 많이 하게 된다면 메모리에 영향을 줄 수도 있습니다.
(최근에는 자바의 컴파일러의 최적화가 진행되면서 문자열의 덧셈 연산시 문제가 많이 해결되었다고는 합니다.)
StringBuilder & StringBuffer
이러한 문자열 + 연산을 하면서 String 객체가 만들어지는 낭비를 방지하고자 StringBuilder와 StringBuffer 클래스가 등장했습니다.
공통점
StringBuilder와 StringBuffer가 갖고 있는 공통점은 다음과 같습니다.
StringBuilder sb = new StringBuilder();
//StringBuffer sb = new StringBuffer(); // 둘 중 아무거나 사용 가능
sb.append("Hello! ");
sb.append("My name is ");
sb.append("Kevin.");
이를 내부적으로 살펴보면 다음과 같습니다.
String이었다면 아래와 같습니다.
StringBuilder, StringBuffer는 append() 메서드를 통해 문자열 값을 가변적으로 추가할 수 있습니다. 이 뿐만 아니라 delete() 메서드를 통해 특정 위치의 문자열을 제거할 수도 있습니다.
차이점
이 둘의 차이점은 스레드 안전함의 보장 여부입니다.
StringBuilder는 자바에서 동기화를 지원하지 않기 때문에 스레드의 안전을 보장하지 않아 단일스레드에서만 사용하는 것이 권장됩니다.
반면에 StringBuffer는 자바에서 동기화를 지원하기 때문에 스레드의 안전을 보장하여 다중스레드에서도 사용이 가능합니다.
특정 메서드 내부에서 생성하고 연산하는 경우에는 StringBuilder를 사용해도 괜찮습니다.
메서드 내부에서 생성되는 지역 변수는 스택 공간에 생성되기 때문에 여러 스레드 사이에서 공유될 수 없기 때문입니다.
public int 아무이름() {
StringBuilder sb = new StringBuilder();
sb.append("hello");
sb.append(" world");
...
return 0;
}
하지만 여러 스레드 사이에 공유되어 사용되는 경우에는 StringBuffer를 사용해야 안전합니다.
public class 아무클래스이름() {
StringBuffer sb = new StringBuffer();
public int 아무이름() {
sb.append("hello");
sb.append(" world");
...
return 0;
}
}