코드 저장소.

String vs StringBuilder vs StringBuffer 본문

Java

String vs StringBuilder vs StringBuffer

slown 2025. 9. 5. 17:40

목차

1.String

2.StringBuilder

3.StringBuffer

4.성능 실험

5.후기

 

1.String

우선 String은 아래와 같은 특징을 가지고 있습니다.

 

1-1.불변객체

 

String은 한 번 생성되면 내부 값을 바꿀 수 없음.

"abc" + "d" → 기존 객체 수정 X , 새로운 객체 생성 O

 

1-2.문자열 상수 풀   

 

String 리터럴은 Heap 영역의 String Pool에 저장됨.

동일한 리터럴을 재사용하여 메모리를 절약.

String a = "hello";
String b = "hello";
System.out.println(a == b); // true

String c = new String("hello");
System.out.println(a == c); // false

 

new String("hello")는 Pool을 무시하고 새로운 객체를 생성

 

1-3.메모리 구조

 

JDK 8까지: 내부적으로 char[]로 문자 저장.

JDK 9부터: 메모리 최적화를 위해 byte[] + coder 플래그로 저장. (Compact Strings)
→ 영어 같은 Latin-1 문자는 1바이트, 한글은 2바이트 차지.

 

1-4.String의 장점

 

불변성 → 스레드 안전, 보안성 높음

상수 풀 덕에 메모리 절약

 

 

2.StringBuilder

StringBuilder는 아래와 같은 특징을 가지고 있습니다.

 

2-1. 가변 객체

 

String과는 다르게 한 번 생성된 후에도 내부 값을 자유롭게 수정 가능.

StringBuilder sb = new StringBuilder("hello");
sb.append(" world"); 
System.out.println(sb.toString()); // hello world

 

2-2. 동작 방식

 

내부적으로 char[] 버퍼를 사용하며, 문자열 조작 시 기존 버퍼를 수정.
버퍼가 가득 차면 자동으로 확장됨.

 

2-3. 동기화 미지원

 

멀티스레드 환경에서는 안전하지 않음.
여러 스레드가 동시에 접근하면 예기치 못한 결과 발생 가능.

 

2-4. StringBuilder의 장점

 

문자열 수정/연산 속도가 매우 빠름

메서드 체이닝(append(), insert(), delete())으로 가독성 높음

단일 스레드 환경에서 문자열 조작에 최적화

3.StringBuffer

StringBuffer는 아래와 같은 특징을 가지고 있습니다.

 

3-1. 가변 객체

 

StringBuilder와 동일하게 문자열을 수정할 수 있음.

StringBuffer sb = new StringBuffer("hello");
sb.append(" world"); 
System.out.println(sb.toString()); // hello world

 

3-2. 동작 방식

 

내부 구조는 StringBuilder와 동일하지만, 모든 메서드에 synchronized 키워드가 붙어 있음.
→ 멀티스레드 환경에서도 안전하게 동작.

 

3-3. 동기화 지원

 

동기화를 제공하지만, 그만큼 불필요한 성능 오버헤드가 존재.
단일 스레드 환경에서는 성능이 StringBuilder보다 떨어짐.

 

3-4. StringBuffer의 장점

 

멀티스레드 환경에서 안전하게 문자열 수정 가능

오래된 레거시 코드나 동기화가 필수적인 상황에서 여전히 사용됨

4.성능 실험

그럼 이 셋의 처리속도를 테스트를 해보기 위해서 간단한 실험을 해보겠습니다. 

 

코드는 아래와 같습니다.

public class Main {

    private static final int ITERATION = 1000000;

    public static void main(String[] args) {
        testString();
        testStringBuffer();
        testStringBuilder();
    }

    private static void testString() {
        long start = System.nanoTime();
        String str = "";
        for (int i = 0; i < ITERATION; i++) {
            str += "a"; // 매번 새로운 객체 생성
        }
        long end = System.nanoTime();
        System.out.println("String: " + (end - start) / 1_000_000 + " ms");
    }

    private static void testStringBuilder() {
        long start = System.nanoTime();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < ITERATION; i++) {
            sb.append("a");
        }
        long end = System.nanoTime();
        System.out.println("StringBuilder: " + (end - start) / 1_000_000 + " ms");
    }

    private static void testStringBuffer() {
        long start = System.nanoTime();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < ITERATION; i++) {
            sb.append("a");
        }
        long end = System.nanoTime();
        System.out.println("StringBuffer: " + (end - start) / 1_000_000 + " ms");
    }
}

 

각각의 방법으로 1000000 수만큼 반복을 해서 처리를 하는 속도를 측정을 해보기로 했고 결과는 아래와 같이 나왔습니다. 

 

결과 해석

  • String: 불변 객체이기 때문에 += 할 때마다 새로운 객체를 생성 → 반복 횟수가 늘어날수록 성능이 기하급수적으로 떨어짐.
  • StringBuffer: 내부 버퍼를 사용하여 빠른 조작이 가능하지만, 모든 메서드가 synchronized 처리되어 있어 Builder보다 다소 느림.
  • StringBuilder: 동기화 처리가 없어서 가장 빠름. 단일 스레드 환경에서 문자열 결합 시 최적.

결론

  • 단순 상수 문자열 → String
  • 단일 스레드에서 문자열 조립/가공 → StringBuilder
  • 멀티 스레드 환경에서 동기화 필요 → StringBuffer

5.후기

이번에 String, StringBuilder, StringBuffer를 직접 성능 비교해보면서, 문법으로만 배웠던 “String은 불변이라서 느리다”라는 말이 숫자로 체감이 되었습니다. 단순히 책에서 읽는 것과 실제로 1,000,000번 돌려본 결과를 보는 건 확실히 다르더군요.

특히 StringBuilder와 StringBuffer의 차이는 생각보다 크지 않았는데, 멀티스레드 환경 여부에 따라 선택 기준이 명확해진다는 걸 알 수 있었습니다.

앞으로는 “무조건 StringBuilder가 빠르다”가 아니라, “상황에 따라 어떤 걸 써야 하는지”를 먼저 생각해야겠다는 걸 배웠습니다.

'Java' 카테고리의 다른 글

== vs equals(), hashCode()  (0) 2025.09.06
Exception 처리 (Checked vs Unchecked)  (0) 2025.09.06
GraalVM?  (0) 2025.08.05
객체 비교를 위한 Comparator , Comparable  (0) 2025.02.06
JVM 내부구조와 동작원리  (0) 2024.05.02