Java에서 String 클래스는 immutable(불변)입니다. 모든 변경 작업 시 새로운 객체가 생성됩니다. StringBuilder와 StringBuffer 클래스는 mutable(가변)이며, 반복문 내에서의 문자열 연결 및 복잡한 변환 작업에 사용됩니다.
주요 차이점:
String: immutable, 추가 동기화 없이 thread-safe. 읽기 쉽고 불변의 텍스트(예: 키, 메시지)에 이상적입니다.StringBuilder: mutable, thread-safe가 아니지만 빠른 연결 속도. 문자가 많이 변경될 때 사용됩니다.StringBuffer: mutable, thread-safe(메소드가 동기화됨) 하지만 StringBuilder보다 성능에서 떨어집니다.속도 비교 예:
String s = ""; for (int i = 0; i < 10000; i++) { s += i; // 매번 새로운 String이 생성되므로 느림! } // 이렇게 하는 것이 더 좋습니다: StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) { sb.append(i); } String result = sb.toString();
단점:
String.intern()은 많은 고유 문자열로 인해 PermGen/Metaspace에서 OutOfMemoryError를 발생시킬 수 있습니다.질문: "반복문 내에서 + 연산자를 사용한 문자열 연결이 효율적입니까?"
답변: 아니요, 매번 새로운 String 객체가 생성되므로 메모리와 GC에 큰 부담을 주게 됩니다. 여러 작업에 대해 StringBuilder 또는 StringBuffer(스레드 안전성이 필요할 경우)를 사용하는 것이 좋습니다.
예:
String s = ""; for (int i = 0; i < 1000; i++) { s += i; // 매우 비효율적임! } // vs StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append(i); }
이야기
은행 프로젝트에서 대규모 반복문 내에서
+연산자를 사용한 문자열 연결로 인해 야간 분석이 15배 느려졌습니다. 문제는 StringBuilder로 교체하여 해결했으며, 실행 시간이 40분에서 2분으로 줄어들었습니다.
이야기
한 신입 개발자가 스레드를 잘못 사용하여 동시에 여러 스레드가 접근하는 동일한 객체에 대해 StringBuilder를 사용했습니다. 이는 동기화 부족으로 인한 우연한 오류와 잘못된 결과를 초래했습니다.
이야기
프로젝트에서는
String.intern()을 사용하여 고유한 레이블을 생성했습니다. 사용자 수가 수천만 명으로 증가하면서 JVM은 OutOfMemoryError: PermGen space를 발생시켰습니다. 우리는 intern() 사용을 중단하고 다른 캐싱 메커니즘으로 전환했습니다.