← 개인 공부 · Java
STUDY NOTE · 개념 정리

String vs StringBuilder vs StringBuffer 정리: 불변 객체와 문자열 풀

Java
String은 불변(immutable), StringBuilder와 StringBuffer는 가변(mutable)이다. 둘 중 StringBuffer만 메서드가 synchronized라 스레드 안전하다. 문자열을 자주 바꾸면 가변 쪽을, 그중 한 스레드에서만 쓰면 StringBuilder를 쓴다.

1. 한눈에 비교

구분StringStringBuilderStringBuffer
변경불가 (바꾸면 새 객체)가능 (내부 배열 수정)가능 (내부 배열 수정)
스레드 안전안전 (애초에 안 바뀜)안전하지 않음안전 (synchronized)
속도이어 붙이기가 많으면 느림가장 빠름락 비용만큼 조금 느림
등장JDK 1.0JDK 1.5JDK 1.0
주 용도값, 키, 상수반복문에서 문자열 조립여러 스레드가 같은 버퍼를 고칠 때 (드묾)

2. String은 왜 불변인가

String s = "hello";
s.concat(" world"); // 새 문자열을 만들어 반환할 뿐, s는 그대로
System.out.println(s); // hello
s = s + " world"; // s가 '새 객체'를 가리키도록 바뀐 것
  1. 문자열 풀(String Pool)을 쓰기 위해: 같은 리터럴은 힙의 풀에서 한 객체를 같이 쓴다. 누가 바꿀 수 있으면 공유할 수 없다.
  2. 해시 캐싱: hashCode()를 한 번 계산하면 저장해 두고 재사용한다. 그래서 HashMap 키로 쓰기 좋다.
  3. 보안: 파일 경로, URL, DB 접속 정보 같은 값이 검사 뒤에 바뀌지 않는다.
  4. 스레드 안전: 바뀌지 않으니 동기화 없이 공유해도 된다.

3. 리터럴 vs new, == vs equals

String a = "java";
String b = "java";
String c = new String("java");

a == b; // true (풀의 같은 객체)
a == c; // false (c는 힙에 새로 만든 객체)
a.equals(c); // true (내용 비교)
a == c.intern(); // true (풀에 있는 객체를 돌려줌)
비교의미
==같은 객체(주소)인가
equals()내용이 같은가 (String이 오버라이드)
intern()풀에 같은 문자열이 있으면 그 객체, 없으면 풀에 넣고 반환

면접 단골: new String("java")는 객체를 몇 개 만드나? 풀에 "java"가 없었다면 리터럴 1개 + 힙 객체 1개로 최대 2개다.

4. + 연산과 StringBuilder

"a" + "b"처럼 컴파일 때 값이 정해진 상수끼리는 컴파일러가 "ab" 하나로 합친다. 변수가 끼면 실행 중에 이어 붙이는데, 반복문 안에서 +=를 쓰면 매번 새 String이 생긴다.

// 나쁨: 반복마다 새 문자열 생성 → 길이 n이면 대략 O(n²) 복사
String s = "";
for (int i = 0; i < 10000; i++) s += i;

// 좋음: 내부 배열 하나를 늘려 가며 수정 → 대략 O(n)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) sb.append(i);
String result = sb.toString();
  1. JDK 9부터 한 줄짜리 + 연결은 invokedynamic(StringConcatFactory)으로 최적화돼서, 반복문이 아닌 곳에선 +를 써도 충분하다.
  2. 크기를 미리 알면 new StringBuilder(용량)으로 배열 확장 횟수를 줄인다. 기본 용량은 16이고, 모자라면 대략 두 배로 늘린다.

5. 정리

  1. 바뀌지 않는 값 → String
  2. 한 스레드에서 문자열 조립 → StringBuilder (대부분의 경우)
  3. 여러 스레드가 같은 버퍼를 고침 → StringBuffer (보통은 설계를 바꾸는 게 낫다)
  4. 내용 비교는 항상 equals(), ==는 같은 객체인지 볼 때만
Gunmo Lee