📝 TIL (Today I Learned) — 2025.09.19.금요일
✍️ 이 글은 내일배움캠프에서 Java 알고리즘 학습 중 문자열 관련 개념을 정리한 TIL입니다.
1. 왜 문자열 처리가 중요할까?
Java에서 문자열은 단순 출력뿐 아니라 알고리즘 문제 풀이, 웹 개발, 실무 애플리케이션에서 가장 자주 쓰이는 데이터 타입입니다.
하지만 같은 문자열 연산이라도 어떤 클래스를 선택하느냐에 따라 성능과 안정성이 크게 달라집니다.
Java는 문자열 처리를 위해 크게 세 가지 클래스를 제공합니다:
- String — 불변(Immutable) 문자열
- StringBuffer — 가변(Mutable) + 스레드 안전
- StringBuilder — 가변(Mutable) + 빠른 성능
2. String — 불변(Immutable)
String str = "Hello";
str += " World"; // 새로운 객체 생성
특징
- 불변(Immutable) → 수정 시마다 새로운 객체 생성
- 동일한 리터럴은 String Pool에서 재사용
장단점
✅ 안정적 (값 변경 불가 → 멀티스레드 환경에서 안전)
✅ Map / Set의 키로 적합
❌ 문자열 연결/수정이 잦으면 매번 객체 생성 → 성능 저하
👉 언제 사용?
문자열 변경이 거의 없을 때, Map/Set의 키로 활용할 때
3. StringBuffer — 가변(Mutable) + 쓰레드 안전
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World"); // 같은 객체 내부에서 수정
System.out.println(sb); // "Hello World"
특징
- 가변(Mutable) → 같은 객체 안에서 문자열 수정
- synchronized 지원 → 멀티스레드 환경에서 안전
장단점
✅ 새 객체 생성 없음 → 효율적
✅ 멀티스레드 환경에서 안전
❌ 단일 스레드에서는 동기화 때문에 성능 손해
👉 언제 사용?
멀티스레드 환경에서 여러 스레드가 같은 문자열을 수정할 때
4. StringBuilder — 가변(Mutable) + 빠른 성능
StringBuilder sb = new StringBuilder();
String result = sb.append("Hello")
.append(" ")
.append("World")
.toString();
System.out.println(result); // Hello World
특징
- StringBuffer와 거의 동일하지만 동기화 미지원
- 단일 스레드 환경에서 최적화
장단점
✅ 불필요한 동기화 없음 → 가장 빠름
❌ 멀티스레드 환경에서는 안전하지 않음
👉 언제 사용?
단일 스레드 환경에서 반복적인 문자열 조작이 필요한 경우
5. 성능 비교 테스트
public class StringPerformanceTest {
public static void main(String[] args) {
int iterations = 100000;
// String 연결 테스트
long start = System.currentTimeMillis();
String str = "";
for (int i = 0; i < iterations; i++) {
str += "a";
}
long stringTime = System.currentTimeMillis() - start;
// StringBuffer 테스트
start = System.currentTimeMillis();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < iterations; i++) {
sb.append("a");
}
long stringBufferTime = System.currentTimeMillis() - start;
// StringBuilder 테스트
start = System.currentTimeMillis();
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sBuilder.append("a");
}
long stringBuilderTime = System.currentTimeMillis() - start;
System.out.println("String: " + stringTime + "ms");
System.out.println("StringBuffer: " + stringBufferTime + "ms");
System.out.println("StringBuilder: " + stringBuilderTime + "ms");
}
}
📊 실행 결과 (100,000회 반복)
| 클래스 | 실행 시간 |
| String | 1161ms |
| StringBuffer | 3ms |
| StringBuilder | 4ms |
➡️ 문자열 연결이 많을 때 String은 압도적으로 느리다는 걸 확인할 수 있습니다.
따라서, 문자열 수정이 많은 상황에서는 String 대신 StringBuilder나 StringBuffer를 선택해야 합니다.
6. 언제 무엇을 써야 할까?
| 클래스 | 특징 | 스레드 안전성 | 성능 | 추천 시나리오 |
| String | 불변 | ✅ O | ❌ 낮음 | 변경 거의 없음, Map/Set 키 |
| StringBuffer | 가변 | ✅ O | ⚖️ 중간 | 멀티스레드 환경 |
| StringBuilder | 가변 | ❌ X | 🚀 빠름 | 단일 스레드, 반복문에서 연결 |
📋 선택 가이드라인
- ✅ 변경 거의 없음 → String
- ✅ 단일 스레드 + 성능 → StringBuilder
- ✅ 멀티스레드 + 안전 → StringBuffer
✨ 오늘의 인사이트
그동안 무심코 String을 사용했지만, 문자열 연결이 많은 경우 성능 저하가 발생할 수 있다는 걸 알게 되었습니다.
특히 알고리즘 문제를 풀 때 문자열 조작이 빈번하게 일어나는 경우, StringBuilder를 활용하면 시간 초과를 피할 수 있을 것 같습니다.
앞으로는 상황에 맞게 String, StringBuffer, StringBuilder를 선택해서 더 효율적인 코드를 작성하겠습니다.
'TIL > 내일배움캠프' 카테고리의 다른 글
| [Spring] IoC 컨테이너와 Bean — 객체를 관리하는 Spring의 방식 (0) | 2025.09.23 |
|---|---|
| [Spring] IoC와 DI — 좋은 코드의 핵심 원칙 (0) | 2025.09.22 |
| [Spring] 자바 웹 개발 흐름 정리 — Servlet부터 Spring Boot까지 (1) | 2025.09.18 |
| [Spring] Spring MVC란? — MVC 패턴과 DispatcherServlet 동작 원리 (0) | 2025.09.17 |
| [Spring/Lombok] 생성자 애너테이션 알아보기 — @AllArgsConstructor, @NoArgsConstructor, @RequiredArgsConstructor (0) | 2025.09.16 |