(숙제) StringBuilder와 StringBuffer는 무슨 차이가 있는가?
String : 문자열
Java에서는 문자열을 다룰 수 있는 객체를 위해 String, StringBuilder, StringBuffer 3가지 클래스를 제공한다.
세 클래스 모두 문자열을 관리하는 클래스라는 공통점이 있지만,
불변(Immutable)인지, 동기화 지원여부에 따라 차이가 있다.
String
[docs]
String class는 불변(immutable)하다.
초기에 생성하면 값이 변하지 않는다는 것이다.
- 인스턴스가 생성되면 수정이 불가능하다.
- String 은 constant 형태로, 한 번 생성이 된다면 update 라는 개념이 사라진다.
- [constant : 상수, 끈임없는]
실제로 자바 코드 정의에서도 final
로 선언 되어있다.
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
private final byte[] value;
...
}
- Immutable 이라는 소리는 결국 값을 수정한다면 새로운 객체를 생성하고 새 값을
재할당
해야 한다는 의미이다.
Java에서 String이 불변(immutable)한 이유
- 동기화 - 멀티스레드 환경
- 안전 - 마음대로 조작 불가
- 성능 - 캐시
1. 동기화
불변객체는 멀티쓰레드(multi-thread)환경에서 안전하다.
값의 변경 가능성이 없기 때문에 멀티 쓰레드 환경에서 동기화 문제를 걱정할 필요가 없다.
2. 안전
여러 참조 변수가 같은 String 객체
를 참조하고 있다고 하더라도 안전하다.
String 객체를 불변으로 만듬으로써 조작할 수가 없기 때문이다.
3. 성능
String을 리터럴로 만들면 String Contstant Poll
이란 영역에 저장된다.
문자열들을 Contstant화 하여 다른 변수나 객체들과 공유하게 되어 성능적 이득을 취할수 있따.
또한 Constant pool을 통해 String을 관리함으로써 재사용을 통해
메모리를 절약할 수 있다.
String은 불변이나, + 같은 연산자 오버라이딩이 되어있어 문자열을 연산할 수 있다.
String helloStr = "hello";
helloStr += "by youngsoo";
System.out.println(helloStr); // 결과 : hello by youngsoo
+
연산자를 통하여 값이 수정된거 같지만 값이 바뀐게 아니다.- hello + by youngsoo 라는 새로운 문자열이 생성되어 다른 메모리 공간에 저장되고, helloStr에서 새 메모리 공간을 참조하는것이다.
- 이것이 왜 가능한지는 String Constant Pool에 대한 내용을 보면 된다.
StringBuilder
[docs]
String 클래스와는 달리 StringBuilder는 가변성(mutable)을 가진다.
- 하지만 내부적으로 동기화 (synchronized)를 지원하지 않는다.
StringBuilder stringBuilder = new StringBuilder("hello");
stringBuilder.append("by youngsoo");
System.out.println(stringBuilder); // 결과 : hello by youngsoo
싱글 스레드 환경이라면 StringBuilder클래스 사용을 권장한다.
StringBuilder*는 *동기화를 지원하지 않기때문에 멀티쓰레드 환경에서 사용하는 것은 적합하지 않지만
동기화를 고려하지 않는 만큼 싱글 스레드에서의 성능은 StringBuffer 보다 뛰어나다
StringBuffer
[docs]
String 클래스와는 달리, StringBuilder 처럼 가변성(mutable)을 가진다. StringBuilder와 동일한 API를 가지고 있다.
StringBuilder와 달리 내부적으로
synchronized 키워드
를 이용해 멀티스레드의 동기화, thread-safe를 보장한다.문자열 연산이 많고 멀티쓰레드 환경일 경우 사용하는 것을 권장한다.
StringBuilder와 StringBuffer의 차이
StringBuilder, StringBuffer 둘은 동일한 API를 가지고 있다.
하지만 가장 큰 차이점은 동기화의 유무이다
StringBuffer는 동기화를 지원하여 멀티쓰레드 환경에서 안전하다는 점(thread-safe) 하고
- 참고로 String도 불변성을 가지기때문에 마찬가지로 멀티쓰레드 환경에서의 안정성(thread-safe)을 가지고 있다.
StringBuilder 동기화를 지원하지 않기때문에 멀티쓰레드 환경에서 사용하는 것은 적합하지 않지만
동기화를 고려하지 않는 만큼 단일쓰레드에서의 성능은 StringBuffer 보다 뛰어나다
String str = "hello"; // 메모리주소를 100이라고 가정
str = str + "by youngsoo"; // 실제로는 101이라는 다른 메모리 공간에 저장된다 (메모리 주소 숫자는 예제를위한 가정이다.)
위의 예제에서 "hello" 값을 가지고 있던 String 클래스의 참조변수 str
이 가리키는 곳에
저장된 "hello"에 "by youngsoo" 문자열을 더해 "hello by youngsoo"로 변경한 것
으로 착각할 수 있다.
하지만 기존의 메모리 100번지에 저장된 "hello" 라는 값에는 그대로 "hello" 가 저장되어있으며,
str (hello) + "by youngsoo" 라는 새로운 값이 생성되어 새로운 메모리 영역인 101번지에 저장되게되고
str은 기존 100번지에서 101번지를 참조하게 되는것이다.
결과적으로 처음 선언했던 100번지의 "hello" 라는 영역은 Garbage가 되어 GC
에 의해 회수된다.
String은 불변하기 때문에 문자열을 수정하는 시점에 새로운 String 인스턴스가 생성된것
결국, String은 불변성을 가지기 때문에,
변하지 않는 문자열을 자주 읽어들이는 경우 String을 (정확히는 리터럴 스트링) 사용해 주면 재사용을 통해 좋은 성능을 기대할 수 있다.
그러나 String의 추가,수정,삭제 등의 연산이 빈번하게 발생하는 알고리즘이 들어가는 로직 등에
String 클래스를 사용하면 힙 메모리(Heap)에 많은 임시 가비지(Garbage)가 생성되어 힙메모리 부족으로 성능에 치명적인 영향을 끼칠 수 있다.
이를 해결하기 위해 Java에서는 가변(mutable)성을 가지는 StringBuffer / StringBuilder 클래스를 도입한것이다.
String, StringBuilder, StringBuffer의 특징
최적화에 따라 다른 성능이 나올 수도 있지만 아래와 같은 특징을 보고 상황에 맞게 적합한 클래스를 사용하는 것이 좋다.
String 과는 반대로 StringBuffer/StringBuilder 는 가변성 가지기 때문에 .append() .delete() 등의 메서드(API)를 이용하여
문자열의 추가,수정,삭제가 빈번하게 발생할 경우라면 String 클래스가 아닌 StringBuffer/StringBuilder를 사용하는것이 좋다.
String : 문자열 연산이 적고 멀티쓰레드 환경일 경우
StringBuilder : 문자열 연산이 많고 단일쓰레드이거나 동기화를 고려하지 않아도 되는 경우
StringBuffer : 문자열 연산이 많고 멀티쓰레드 환경일 경우
String | StringBuilder | StringBuilder | |
---|---|---|---|
저장 위치(Storage) | String pool (Contstant Pool) | Heap | Heap |
수정여부(immutable) | 불변 (Immutable) | 가변 (mutable) | 가변 (mutable) |
쓰레드 안전여부 (Thread safe) | 안전 | 불안전 | 안전 |
동기화 여부 (Synchronized) | 지원 | 미지원 | 지원 |
성능 (Performance) | 빠름(fast) | 느림(slow) | 빠름(fast) |
'Java > Java' 카테고리의 다른 글
Java - 동일성과 동등성 ( ==, equals() ) (0) | 2022.11.19 |
---|---|
Java 박싱과 언박싱, 오토박싱 그리고 성능상 주의할점 (0) | 2022.11.13 |
Java 람다표현식의 특징과 Scope, effectively final variable (0) | 2022.10.23 |
Java String Pool (String Constant Pool) + String.intern() (0) | 2022.10.21 |
# Java 그룹화, 그룹화 하고 정렬. Stream groupby, groupingBy, sorting Lists after groupingBy (0) | 2022.09.07 |