[CS] 자바의 정석 독서 #17 - StringBuffer, StringBuilder

2025. 11. 19. 07:02·언어공부/Java | Kotlin

어제는 String에 대해서 알아봤는데,

String은 불변객체기 때문에 값을 수정하거나 새로운 값을 저장할 때마다 새로운 String 객체가 생성된다.

 

간단한 프로젝트나 현재의 JVM환경에서는 크게 못 느낄지 몰라도 메모리 낭비가 될 수 있기 때문에, 값을 수정해도 새 객체를 생성하지 않고 기존객체에서 문자열을 수정할 수 있는 StringBuffer를 사용하는 경우가 있다.

 

또 StringBuffer는 스레드안전하기도하고


StringBuffer & StringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence {

    byte[] value;

    byte coder;
    
    ...
}

StringBuffer와 StringBuilder는 문자열을 다루기 위한 클래스이다. 두 클래스의 공통조상인 AbstractStringBuilder가 내부적으로 char[]를 사용했으나 JDK9이후로 내부적으로는 byte[] 를 사용한다.

 

String과 차이점으로는 StringBuffer의 value는 가변이라서 배열의 내용을 변경할 수 있다. String의 내부 byte[]를 변경하면 그냥 새 객체가 생성되는 것과 달리 StringBuffer와 StringBuilder는 내부 byte[]를 변경하면 새 객체가 생성되지 않는다.

 

이게 StringBuffer 클래스의 큰 목적이다. 가변적인 문자열 선언


StringBuffer sb = new StringBuffer("Java");
StringBuffer sb2 = new StringBuffer(16);

생성자는 다음과 같이 사용한다.

생성자의 인자로는 String, int, CharSequence를 받는다. int는 byte[]의 크기를 지정하게되고, 나머지 둘은 그 내용을 byte[]에 저장하게된다.

 

AbstractStringBuilder(int capacity) {
        if (COMPACT_STRINGS) {
            value = new byte[capacity];
            coder = LATIN1;
        } else {
            value = StringUTF16.newBytesFor(capacity);
            coder = UTF16;
        }
    }

    
AbstractStringBuilder(String str) {
    int length = str.length();
    int capacity = (length < Integer.MAX_VALUE - 16)
            ? length + 16 : Integer.MAX_VALUE;
    final byte initCoder = str.coder();
    coder = initCoder;
    value = (initCoder == LATIN1)
            ? new byte[capacity] : StringUTF16.newBytesFor(capacity);
    append(str);
}

위 생성자를 보면 int가 생성자로 전해지면 LATIN-1로 인코딩된 경우 내부 byte[]를 capacity 크기만큼 설정하고,

String이 생성자로 전해지면 String의 길이의 16만큼 더해서 내부 byte[] 크기를 설정하고 String을 넣어 반환한다.

 

@IntrinsicCandidate
    public StringBuffer() {
        super(16);
    }

    @IntrinsicCandidate
    public StringBuffer(int capacity) {
        super(capacity);
    }


    @IntrinsicCandidate
    public StringBuffer(String str) {
        super(str);
    }
}

그리고 StringBuffer는 super() 생성자를 통해 위 생성자들을 호출한다.

StringBuffer는 AbstractStringBuffer의 하위클래스다.


StringBuffer 값변경

public static void main(String[] args) {
    StringBuffer sb = new StringBuffer("String");
    sb.append("Buffer");

    System.out.println(sb.toString());
}

이러면 생성자를 통해 내부 바이트배열에 String 이 저장되고, .append() 메서드를 통해 문자열 뒤에 문자열을 추가할 수 있다.

String이라면 문자열 뒤에 문자열을 추가했으면 새로운 객체가 생성됐겠지만 StringBuffer는 내부 배열에 추가된 문자열을 추가한다.

 

StringBuffer sb = new StringBuffer("String");
StringBuffer sb2 = sb.append("Buffer");

StringBuffer sb3 = sb.append(" test").append("ing...");

append() 메서드의 반환값은 자신의 주소다. 그렇기 때문에 이를 다른 StringBuffer에 대입할 수도 있고 .append() 메서드에 .append()메서드를 적용시킬 수도 있다. 만약 반환타입이 void였다면 불가했을 것이다.

 

다만 주의해야할 점으로는 같은 주소를 참조하고 있으면 내부 배열도 같이 공유하기 때문에, 위의 예시에서 sb와 sb2, sb3는 같은 값을 공유한다.


StringBuffer 값변경

 

StringBuffer sb = new StringBuffer("String");
StringBuffer sb2 = new StringBuffer("String");

System.out.println(sb.equals(sb2));	//false
System.out.println(sb == sb2);		//false

String은 equals() 메서드를 오버라이딩했으나 StringBuffer는 그렇지 않았다. 그래서 .equals() 메서드를 사용하면 등가연산(==)과 동일하게 작동하여 두 객체가 같은 객체를 참조 중인지만 조사한다.

 

System.out.println(sb.toString().equals(sb2.toString())); //true

그렇기 때문에 값을 비교하려면 .toString()을 사용하여 String으로 변환한 뒤에 비교해야한다. (.toString()은 오버라이드되어있다.)


기타 메서드

생성자와 append() 외에 꽤 쓸만한 메서드들은

StringBuffer sb = new StringBuffer("String");

System.out.println(sb.capacity());	//22

- capacity() StringBuffer 인스턴스의 버퍼 크기를 알려준다. 내부 바이트배열의 크기이다. 생성자 관련된 코드에서 볼 수 있듯이 기본 바이트배열의 크기는 (String 값이 주어진 경우) String의 크기 + 16, (int 값이 주어진 경우) int 값으로 설정된다.

 

- length() 문자열의 길이를 반환한다. capacity()와 다르다.

 

StringBuffer sb = new StringBuffer("String");

System.out.println(sb.delete(1,3));		//Sing
System.out.println(sb.deleteCharAt(0));	//ing

- delete(int start, int end)  주어진 인덱스 범위에서 값을 제거한다.

- delete(int index)  주어진 인덱스에서의 값을 제거한다. 뒤에 있는 문자배열의 값도 하나씩 앞으로 옮긴다.

 

- index (int index, Object obj) 지정된 위치에 값을 추가한다. Object 위치에는 아무 기본형변수나 String도 들어올 수 있다. 단지 글이 길어져서 생략했다..

 

StringBuffer sb = new StringBuffer("String");

System.out.println(sb.toString().repeat(3));	//StringStringString

- repeat (int codepoint, int count) 문자 또는 문자열을 count번만큼 반복하여 끝에 추가한다. JDK21부터 가능하다. 나는 JDK17이라 못 쓰는데 이 때는 String으로 변환하여 String의 .repeat() 메서드를 사용해야한다. 다만 String의 .reapeat() 메서드는 전체 반복만 할 수 있다.

 

- reverse() 거꾸로 진행한다.

StringBuffer sb = new StringBuffer("String");

System.out.println(sb.substring(0,2));		//St
System.out.println(sb.substring(3));		//ing

- subString(int start, int end)  지정된 범위만큼 String으로 반환한다. end값을 지정하지 않아도되는데 그럴 땐 문자열의 끝까지 반환한다. end값의 앞까지 반환되는 인덱스에 해당한다.

 

이정도가 있겠다.


StringBuilder

StringBuffer는 멀티스레드에 안전하도록 동기화되어있다. 스레드를 배우고나서 다시 하겠지만..

어쨌든 멀티스레드 환경에서 동기화가 StringBuffer의 성능을 떨어트린다. 그래서 동기화 부분을 제거한 StringBuilder가 사용된다. 이 점만 제외하면 둘은 완벽하게 동일하다.

 

굳이 성능향상이 필요한 경우가 아니라면 StringBuffer를 모두 StringBuilder로 바꿀 필요는 없다.

'언어공부 > Java | Kotlin' 카테고리의 다른 글

[CS] 자바의정석 독서 #19 - ArrayList, Vector, LinkedList  (1) 2025.11.21
[CS] 자바의정석 독서 #18 - 컬렉션은 무엇인가?  (1) 2025.11.20
[CS] 자바의 정석 독서 #16 - String 클래스 파헤치기  (0) 2025.11.18
[CS] 자바의 정석 독서 #14 - 예외처리  (0) 2025.11.11
[CS] 이펙티브 자바 독서 #3 - 아이템85. 직렬화를 피하라!  (0) 2025.10.23
'언어공부/Java | Kotlin' 카테고리의 다른 글
  • [CS] 자바의정석 독서 #19 - ArrayList, Vector, LinkedList
  • [CS] 자바의정석 독서 #18 - 컬렉션은 무엇인가?
  • [CS] 자바의 정석 독서 #16 - String 클래스 파헤치기
  • [CS] 자바의 정석 독서 #14 - 예외처리
Radiata
Radiata
개발을 합니다.
  • Radiata
    DDD
    Radiata
  • 전체
    오늘
    어제
    • 분류 전체보기 (211)
      • 신년사 (3)
        • 2025년 (2)
        • 2026년 (1)
      • CS (59)
        • JVM (12)
        • 백엔드 (20)
        • 언어구현 (1)
        • 객체지향 (1)
        • 논리회로 (5)
        • 컴퓨터구조 (9)
        • 데이터베이스 (1)
        • 컴퓨터 네트워크 (10)
      • 언어공부 (64)
        • Java | Kotlin (48)
        • JavaScript | TypeScript (9)
        • C | C++ (6)
      • 개인 프로젝트 (11)
        • [2025] Happy2SendingMails (3)
        • [2026] 골든리포트! (8)
        • [2026] 순수자바로 개발하기 (0)
        • 기타 이것저것 (0)
      • 팀 프로젝트 (29)
        • [2025][GDG]홍대 맛집 아카이빙 프로젝트 (29)
      • 알고리즘 (13)
        • 백준풀이기록 (11)
      • 놀이터 (0)
      • 에러 수정일지 (2)
      • 고찰 (24)
        • CEOS 23기 회고록 (2)
  • 블로그 메뉴

    • CS
    • 언어공부
    • 개인 프로젝트
    • 팀 프로젝트
    • 알고리즘
    • 고찰
    • 신년사
    • 컬러잇 개발블로그
  • 링크

    • 컬러잇 개발블로그
  • 공지사항

  • 인기 글

  • 태그

    144
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Radiata
[CS] 자바의 정석 독서 #17 - StringBuffer, StringBuilder
상단으로

티스토리툴바