JAVA - String, StringBuffer, StringBuilder

황제연·2025년 7월 13일
0

CS학습

목록 보기
134/193
post-thumbnail

자바의 String 객체

자바의 String 객체는 불변이기 때문에, 문자열을 수정하는 연산을 할 때마다
새로운 String 인스턴스가 생성됩니다

그렇기 때문에, 반복문에서 문자열을 누적하면 매 반복마다
새로운 문자열 객체가 힙 메모리에 쌓여 성능이 저하됩니다

이것이 문자열 수정 연산으로 인한 성능 이슈입니다

StringBuffer와 StringBuilder 활용

따라서 불변의 문제를 해결하기 위해,
문자열을 이어붙일 때는 String 대신 가변 문자열 클래스를 사용해야 합니다
그리고 그 대안으로 StringBuffer와 StringBuilder를 활용할 수 있습니다

StringBuffer (멀티스레드 환경)

StringBuffer는 멀티스레드 환경에서 사용할 수 있도록
내부 연산에 동기화(synchronized)가 적용되어 thread-safe합니다
다만, 동기화로 인한 약간의 성능 저하가 있습니다.

StringBuilder (단일 스레드 환경)

StringBuilder는 동기화를 지원하지 않지만, 그만큼 동작이 빠르고 가볍습니다
따라서 단일 스레드 환경이나 thread-safe가 필요 없는 경우 가장 좋은 선택입니다

문자열 연결(+) 연산의 컴파일러 최적화 (JDK 5.0부터)

JDK 5.0부터 자바 컴파일러는 문자열을 +로 더하는 코드를 자동으로
StringBuilder를 사용하도록 최적화합니다
예를 들어 str1 + str2 + str3는 컴파일 시
new StringBuilder().append(str1).append(str2).append(str3).toString()
형태로 변환됩니다

하지만 컴파일러 최적화에도 불구하고, 반복문 안에서 +를 사용하면 여전히 비효율적일 수 있습니다.
매 반복마다 새로운 StringBuilder와 String 객체가 생성되기 때문입니다
해결책은 루프 밖에서 StringBuilder를 생성하고, 루프 안에서는 append()만 호출한 후
마지막에 toString()을 호출하는 방식입니다

Invokedynamic을 활용한 문자열 결합 최적화 (Java 9+)

Java 9부터 도입된 JEP 280("Indify String Concatenation")에 의해,
문자열 결합(+ 연산)은 컴파일 타임이 아닌 런타임에 최적의 방법으로 수행됩니다.

주요 특징

  • 컴파일러는 과거처럼 고정된 StringBuilder 코드로 변환하지 않고,
    invokedynamic 명령을 통해 JVM에게 문자열 결합 방법을 맡깁니다.
  • 런타임에 JVM은 결합되는 문자열의 수와 길이를 고려하여 최적의 방법(버퍼 크기 미리 할당, 중간 객체 최소화)을 자동으로 결정합니다

따라서 작은 규모의 문자열 결합은 개발자가 최적화하지 않아도 충분히 빠르게 동작합니다
그러나 매우 큰 문자열을 반복해서 연결하는 경우에는 여전히 명시적으로 최적화하는 것이 좋습니다

Compact Strings 및 메모리 개선 (Java 9+)

Java 9에서 도입된 JEP 254("Compact Strings") 기능을 통해, 문자열의 메모리 효율이 크게 개선되었습니다

핵심 원리

ASCII 기반 문자만 포함된 문자열은 1바이트-per-문자 형식으로 저장됩니다.
그 외의 문자가 포함된 경우에는 기존처럼 2바이트-per-문자 형식으로 저장됩니다.

실질적인 장점

영어, 숫자, 공백 등으로 이루어진 대다수의 문자열에서 메모리 사용량이 최대 절반까지 줄어듭니다.
이를 통해 GC(Garbage Collection) 부하가 감소하며, 애플리케이션의 전반적인 성능 향상에 기여합니다.

다양한 문자열 처리 방식의 성능 비교

방식특징성능
StringBuilder명시적인 버퍼 관리, 반복적 문자열 생성에 최적빠름 (반복적인 경우 가장 좋음)
String.format가독성 및 포맷팅 편의성 좋음상대적으로 느림 (성능이 중요한 경우 지양)
문자열 + 연산 (invokedynamic)작은 규모 문자열 처리에 매우 효율적빠름 (적당한 크기의 문자열)
  • 따라서 작은 문자열 연결의 경우 + 연산자를 사용해도 무방하지만,
  • 반복적인 문자열 결합이나 긴 문자열 처리에서는 여전히 명시적인 StringBuilder가 권장됩니다

4. Java 21 문자열 템플릿(String Templates)

Java 21에서는 문자열 템플릿(JEP 430)이 제공됩니다.
더 간결하고 효율적인 문자열 처리를 지원합니다.

문법 예시

String name = "World";
String greeting = STR."Hello, \{name}!";
// 출력: "Hello, World!"
  • String.format보다 빠르며, 문자열 + 연산과 비슷하거나 더 좋은 성능을 제공합니다.
  • 명확한 코드 가독성과 성능을 동시에 충족합니다

정리

  • 작은 규모의 문자열 연결: 가독성을 위해 + 연산자를 적극 사용해도 성능상 문제 없습니다
  • 반복적으로 긴 문자열 연결: 여전히 명시적인 StringBuilder 사용을 권장합니다

참고

  • 자바 성능 튜닝 이야기 - 3챕터
profile
Software Developer

0개의 댓글