TIL/내일배움캠프

[Java] 문자열 다루기 — String, StringBuffer, StringBuilder 차이

bu119 2025. 9. 19. 18:00
728x90
반응형

📝 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를 선택해서 더 효율적인 코드를 작성하겠습니다.

728x90
반응형