본문으로 건너뛰기
홈
기술
기술 전체
프로그래밍68
컴퓨터 과학63
AI48
웹 개발36
인프라33
데이터31
소프트웨어 공학18
소개
← 목록으로프로그래밍 › Java › 기초

String 보다는 StringBuilder, StringBuffer를 사용해야하는 이유.

목차

String, StringBuilder, StringBuffer를 언제 사용할까?

문자열을 몇 개 이어 붙이는 코드에 StringBuilder를 무조건 쓰라는 규칙은 없다. Java의 String은 불변이므로 text += piece를 루프에서 반복하면 이전 문자열을 토대로 새 문자열 결과를 계속 만든다. 입력이 커질수록 복사할 문자도 늘 수 있다. 반면 StringBuilder는 내부에 변경 가능한 문자 시퀀스를 두고 append로 이어 붙인다. 반복적·누적적 연결이 필요한 곳에서 의미가 분명하다.

원문 벤치마크는 String 루프가 9만 회, 다른 루프가 1천만 회였고, StringBuilder 측정 구간에서도 실수로 sb.append를 호출했다. 따라서 제시된 44초·0.9초 같은 수치는 세 방식의 성능 비교 근거로 사용할 수 없다. JVM 준비 상태, 결과 사용 여부, 메모리, 입력 길이도 측정에 영향을 준다.

값을 누적하는 예제

public class JoinExample {
    static String join(String[] parts) {
        StringBuilder builder = new StringBuilder();
        for (String part : parts) {
            if (builder.length() > 0) builder.append(", ");
            builder.append(part);
        }
        return builder.toString();
    }

    public static void main(String[] args) {
        System.out.println(join(new String[] {"A", "B", "C"}));
        // A, B, C
    }
}

루프에서 연결을 반복해도 builder 객체를 계속 사용한다. append(part + "=")라고 쓰면 그 표현식의 문자열 연결이 append 호출 전에 평가될 수 있다. 의도적으로 임시 문자열을 피하려면 builder.append(part).append('=')처럼 연결한다. 그렇다고 part + "=" 한 번이 항상 성능 문제라는 뜻은 아니다. 작은 한 문장은 +가 읽기 쉬울 수 있고, 컴파일러와 JVM의 최적화도 있다.

StringBuffer는 무엇이 다른가

StringBuffer는 주요 메서드가 동기화되어 여러 스레드에서 하나의 버퍼를 사용할 수 있다. StringBuilder는 같은 동기화 보장을 하지 않는다. 그러나 StringBuffer의 개별 append()가 동기화되어도 여러 호출을 하나의 원자적 업무 연산으로 묶어주지는 않는다. 두 스레드가 append(name); append("="); append(value);를 각각 실행하면 호출 사이에 내용이 섞일 수 있다. 한 결과 문자열의 소유자를 한 스레드로 제한하거나 외부에서 전체 연산을 보호해야 한다.

메서드의 지역 StringBuilder를 각 호출이 새로 만들면 자연스럽게 스레드마다 분리된다. 정적 필드라는 이유만으로 StringBuffer를 선택하기보다 공유 변경 상태가 정말 필요한지 먼저 본다. 결과를 순서대로 합치는 일이라면 각 작업의 결과를 따로 만들고 마지막에 조합하는 편이 쉬울 수 있다.

상황먼저 선택할 표현
짧은 한 줄을 조합String의 + 또는 템플릿 표현
루프에서 계속 덧붙임지역 StringBuilder
구분자로 목록 결합String.join 또는 StringJoiner
여러 스레드가 버퍼를 공유공유 설계를 재검토하고 필요 시 StringBuffer/외부 동기화

표는 코드의 의도를 기준으로 한 선택표다. 메모리와 처리량이 실제 병목이면 같은 길이와 같은 반복 수로 벤치마크하고 결과 문자열을 소비해야 한다. JIT가 작업을 제거하거나 GC 상태가 달라지는 상황을 피하려면 전용 벤치마크 도구(JMH) 같은 방법이 필요하다. 원문의 고정된 응답 시간·메모리 순위는 이런 조건 없이 일반화할 수 없다.

참고: Oracle StringBuilder API, StringBuffer API, OpenJDK JMH

같은 카테고리의 글