Java에서 String, StringBuilder, StringBuffer 차이점 정리

오형상·2025년 2월 5일
0

java

목록 보기
8/9
post-thumbnail

Java에서 문자열을 다룰 때 가장 많이 사용하는 클래스는 String, StringBuilder, StringBuffer입니다. 하지만 각각의 특성과 사용 용도가 다르기 때문에 올바르게 선택하는 것이 중요합니다. 이번 글에서는 이 세 가지 클래스의 차이점과 어떤 상황에서 어떤 클래스를 사용해야 하는지 정리해 보겠습니다.


1. String (불변 객체, Immutable)

String 클래스는 불변(Immutable) 한 객체입니다. 즉, 문자열을 변경하면 새로운 객체가 생성되며, 기존 객체는 변경되지 않습니다.

특징

  • 불변성: 한 번 생성된 문자열은 변경할 수 없음.
  • 힙 메모리 내 String Pool 사용: 동일한 문자열이 여러 개 존재할 경우 String Pool을 사용하여 중복을 방지.
  • 성능 이슈: 문자열이 자주 변경될 경우 성능이 떨어질 수 있음 (새로운 객체가 계속 생성되므로 메모리 낭비 발생).

예제

String str1 = "Hello";
String str2 = str1 + " World"; // 새로운 String 객체가 생성됨
System.out.println(str1); // Hello
System.out.println(str2); // Hello World

2. StringBuilder (가변 객체, Mutable, 비동기)

StringBuilder가변(Mutable) 객체로, 문자열을 수정할 때 새로운 객체를 생성하지 않고 기존 객체의 내부 배열을 변경합니다.

특징

  • 가변성: 문자열을 변경할 수 있음.
  • 비동기(스레드 안전하지 않음): 멀티 스레드 환경에서는 안전하지 않음.
  • 빠른 성능: String보다 문자열 변경이 많은 경우 성능이 뛰어남.

예제

StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // 기존 객체에 문자열을 추가
System.out.println(sb); // Hello World

3. StringBuffer (가변 객체, Mutable, 동기)

StringBufferStringBuilder와 동일하지만 스레드 안전(Thread-safe) 합니다. 내부적으로 synchronized 키워드를 사용하여 멀티 스레드 환경에서도 안전하게 동작합니다.

특징

  • 가변성: 문자열을 변경할 수 있음.
  • 동기화 지원 (Thread-safe): 멀티 스레드 환경에서도 안전하게 동작.
  • 느린 성능: synchronized 사용으로 인해 StringBuilder보다 성능이 낮음.

예제

StringBuffer sb = new StringBuffer("Hello");
sb.append(" World"); // 기존 객체에 문자열을 추가
System.out.println(sb); // Hello World

4. String, StringBuilder, StringBuffer 비교 정리

StringStringBuilderStringBuffer
가변성불변 (Immutable)가변 (Mutable)가변 (Mutable)
성능느림 (새로운 객체 생성)빠름 (객체 재사용)상대적으로 느림 (synchronized 사용)
스레드 안전성O (String 자체가 불변이라 안전)X (스레드 안전하지 않음)O (synchronized 사용)
사용 추천 환경변경이 거의 없는 문자열단일 스레드에서 문자열 변경이 많은 경우멀티 스레드에서 문자열 변경이 많은 경우

5. String, StringBuilder, StringBuffer 성능 비교 테스트

다음은 세 가지 클래스를 활용한 성능 테스트 코드입니다.

public class StringPerformanceTest {
    public static void main(String[] args) {
        long startTime, endTime;

        // String 테스트
        startTime = System.nanoTime();
        String str = "";
        for (int i = 0; i < 10000; i++) {
            str += i; // 매번 새로운 객체가 생성됨
        }
        endTime = System.nanoTime();
        System.out.println("String 실행 시간: " + (endTime - startTime) / 1_000_000 + "ms");

        // StringBuffer 테스트
        startTime = System.nanoTime();
        StringBuffer sbf = new StringBuffer();
        for (int i = 0; i < 10000; i++) {
            sbf.append(i); // 기존 객체에 추가됨
        }
        endTime = System.nanoTime();
        System.out.println("StringBuffer 실행 시간: " + (endTime - startTime) / 1_000_000 + "ms");
        
        // StringBuilder 테스트
        startTime = System.nanoTime();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10000; i++) {
            sb.append(i); // 기존 객체에 추가됨
        }
        endTime = System.nanoTime();
        System.out.println("StringBuilder 실행 시간: " + (endTime - startTime) / 1_000_000 + "ms");
    }
}

실행 결과 (환경에 따라 다를 수 있음)

String 실행 시간: 76ms
StringBuilder 실행 시간: 0ms
StringBuffer 실행 시간: 1ms
  • String객체가 계속 생성되므로 매우 느림
  • StringBuffersynchronized로 인해 약간 느림
  • StringBuilder가장 빠름

0개의 댓글

관련 채용 정보