들어가며
이 글에서는 StringBuilder, StringBuffer 차이점뿐만 아니라 사용 이유에 대해서도 다루고있습니다.
[JAVA] String의 불변성(immutability)
들어가며JAVA를 처음 접할 때, String은 불변객체라고 배우고 지나갔습니다. 하지만 실제 String을 다루다보면 어째서 불변객체인지 의문이 들곤합니다. String str = "apple"; str = "banana";왜냐하면, 재할
tmd8633.tistory.com
이전 글에서 String의 불변성에 대해서 읽어보시는걸 추천드립니다.
불변성
String 은 불변성입니다.
StringBuffer, StringBuilder 는 가변성입니다.
String str = "1";
System.out.println("hashCode = " + str.hashCode());
System.out.println("====================================");
String[] arr = {"2", "3", "4"};
for (String s : arr) {
str += s;
System.out.println("hashCode = " + str.hashCode());
}
// hashCode = 49
// ====================================
// hashCode = 1569
// hashCode = 48690
// hashCode = 1509442
String은 불변객체이기때문에 String Constant Pool에서 str += s 될때마다 불필요한 새로운 데이터를 heap 영역에 저장합니다.
System.out.println("12".hashCode()); // 1569
실제로 중간과정에서 만들어진 String의 hashCode를 가져와보면 Pool에서 불필요한 데이터가 저장된걸 볼 수 있습니다.
여기에서 StringBuffer or StringBuilder를 사용하면 어떻게 될까요?
StringBuilder sb = new StringBuilder("1");
System.out.println("hashCode = " + sb.hashCode());
System.out.println("====================================");
String[] arr = {"2", "3", "4"};
for (String s : arr) {
sb.append(s);
System.out.println("hashCode = " + sb.hashCode());
}
// hashCode = 918221580
// ====================================
// hashCode = 918221580
// hashCode = 918221580
// hashCode = 918221580
가변객체이기때문에 hashCode가 변하지 않은것을 확인할 수 있습니다.
String의 불변특성때문에 문자열 더하기의 연산은 불필요한 데이터를 저장하게되며, hashCode의 캐싱에도 불필요한 데이터가 저장된다는 문제가 있습니다. 따라서 String의 문자열 더하기는 StringBuilder 나 StringBuffer를 사용하도록 해야합니다.
그러면 StringBuilder와 StringBuffer는 무슨 차이가 있을까요?
StringBuilder vs StringBuffer
Builder와 Buffer는 같은 추상클래스를 상속받고 있고, 그 구조가 완벽하게 동일합니다. 그 차이점은 구현체에서 찾을 수 있습니다.
StringBuffer는 동기화를 지원하고 (Thread-Safe),
StringBuilder는 동기화를 지원하지 않습니다.
StringBuffer 대부분의 메소드에는 synchronized 키워드가 붙어있습니다.
언제 어떻게 사용하면 될까?
StringBuffer
동기화를 지원하기때문에 멀티스레드 환경에서 안전하게 동작합니다. 동시성 문제를 고려해야한다면 StringBuffer를 사용해야합니다.
StringBuilder
StringBuilder는 StringBuffer 보다 일반적으로 성능상 빠릅니다. 동기화 처리가 없기 때문입니다. 따라서 단일스레드 환경에서는 불필요한 동기화 처리를 하지 않는 StringBuilder를 사용해야합니다.
사용 시 주의점
1. capacity
StringBuilder, StringBuffer 둘다 용량증가정책은 동일하게 설정되어있습니다. 이 capacity는 문자열의 수용량입니다. 기본 capacity는 16입니다.
Collection List를 최적화해보자
Collection List Collection중에 가장 많이 사용하는 것은 아마도 List일것입니다. List에는 여러 구현체가 있습니다. ArrayList, LinkedList, Vector 가 있는데 오늘 알아볼것은 ArrayList와 LinkedList입니다. 최적화
tmd8633.tistory.com
이전 글에서 List의 최적화를 다뤘는데 List의 initialCapacity와 같은 개념입니다.
append 메소드를 사용할때, capacity가 가득차면 추상클래스에서 ensureCapacityInternal 메소드를 통해 capacity를 2배증가시킵니다.
이 과정에서 StringBuffer는 동기화 처리과정에서 오버헤드가 발생할 수 있습니다. (락 획득과 해제, 락에 의한 대기시간 증가 등)
capacity는 생성자에서 사용자가 조절할 수 있습니다.
2. null 처리
String str = null;
StringBuilder sb = new StringBuilder("1");
sb.append(str);
System.out.println("sb = " + sb); // sb = 1null
StringBuffer sb2 = new StringBuffer("1");
sb2.append(str);
System.out.println("sb2 = " + sb2); // sb2 = 1null
String a = "1";
a += str;
System.out.println("a = " + a); // a = 1null
StringBuilder, StringBuffer 에 null이 append 되었을 때 따로 처리해주지 않습니다. null 이 들어오면 "null" 문자열로 인식되어 append 됩니다. 사용하기 전에 null 처리를 반드시 해야됩니다.
'Language > JAVA' 카테고리의 다른 글
[JAVA] for문과 향상된 for문은 어떤 차이가 있을까? (0) | 2024.09.24 |
---|---|
[JAVA] If-else 와 switch 중에 어느게 더 빠를까? (0) | 2024.09.24 |
[JAVA] String의 불변성(immutability) (0) | 2024.09.23 |
[JAVA] 함수형 인터페이스에 대해서 알아보자 (0) | 2024.09.15 |
[JAVA] Collection List를 최적화해보자 (0) | 2024.03.18 |