Java에서 문자열을 다룰 때, 사용이 간편한 String 타입을 많이 사용합니다.
하지만 불변 객체(immutable object) 라 수정 시 메모리에 새로운 문자열 객체를 계속 만들어 성능 저하가 발생합니다.
StringBuilder는 "char[] "기반인 가변 객체(mutable object)로 문자열 조작(추가, 삭제, 삽입)시 성능이 빠르고 효율적입니다.
Java 9 이후부터는 메모리 효율을 위해 "byte[] "를 사용합니다.
// Java 11 기준입니다.
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable {
public StringBuilder() {
super(16); // AbstractStringBuilder(16) 호출합니다.
}
public StringBuilder append(String str) {
super.append(str); // AbstractStringBuilder의 append(str) 메서드를 호출합니다.
return this;
}
public String toString() {
return new String(value, 0, count);
}
}
// 부모 클래스
abstract class AbstractStringBuilder {
char[] value;
int count;
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
void ensureCapacityInternal(int minimumCapacity) {
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
value = Arrays.copyOf(value, newCapacity);
}
}
초기화 시 보통 16개의 문자를 담을 수 있는 빈 배열을 기본적으로 만듭니다.
새로운 문자열을 추가(append)할 때, 내부에서는 다음과 같은 판단을 내립니다.
공간이 충분한가?
- 현재 추가할 길이를 계산해서 value.length보다 작으면 그냥 배열 뒤에 글자를 써넣습니다.
공간이 부족한가?
- 만약 16칸이 꽉 찼는데 글자를 더 넣으려고 하면, 배열의 크기를 대략 2배로 키운 새로운 큰 배열을 만듭니다. 그리고 기존 배열의 내용을 새 배열로 복사한 뒤 작업을 이어갑니다.
메서드 (Method)
| 이름 | 설명 |
|---|---|
| value | 실제 문자열 저장소로 초기 크기는 16글자 크기입니다. |
| length() | 문자열의 길이를 확인합니다. |
| insert(int index, String str) | 파라미터 index에 파라미터의 문자열을 삽입합니다. |
| replace(int index1, int index2) | index1에 해당하는 문자열과 index2에 해당하는 문자열의 위치를 바꿉니다. |
| substring(int start, int end) | start부터 end까지 해당하는 문자열을 출력합니다. 파라미터가 start만 있으면, start부터 끝까지 문자열 출력, |
| deleteCharAt(int index) | index에 위치한 문자 하나를 삭제합니다. |
| delete(int start, int end) | start부터 end - 1까지의 문자를 삭제합니다. |
| reverse() | 문자열 숫자를 뒤집습니다. |
| append(String str) | 문자열을 삽입하는 메서드입니다. |
| toString() | String 타입으로 변경 시키는 메서드입니다. |
| setLength(int len) | 문자열 길이를 조정합니다. 문자열이 len 보다 길면 나머지 문자가 삭제되고, 짧으면 공백으로 채워집니다. |
| setCharAt(int index, String char) |
index 위치에 해당하는 문자열을 char로 수정합니다. |
| expandCapacity( ) ensureCapacityInternal( ) |
공간이 부족하면 배열 크기를 증가시키는 메서드 입니다. |
사용 예시
public class StringBuilderExample {
public static void main(String[] args) {
// 1. 객체 생성 (기본 16칸짜리 배열 생성)
StringBuilder sb = new StringBuilder("Java");
// 2. append(): 뒤에 데이터 추가
// 어떤 타입(int, double, boolean 등)이든 문자열로 변환해서 붙여줍니다.
sb.append(" Study"); // "Java Study"
sb.append(17); // "Java Study17"
// 3. insert(인덱스, 값): 특정 위치에 삽입
sb.insert(4, " Script"); // 인덱스 4번 위치에 " Script" 삽입
// 결과: "Java Script Study17"
// 4. replace(시작, 끝, 값): 범위 지정 교체
// 인덱스 0부터 4 직전까지를 "Type"으로 변경
sb.replace(0, 4, "Type");
// 결과: "Type Script Study17"
// 5. delete(시작, 끝): 범위 지정 삭제
// " Study" 부분(인덱스 10~16) 삭제
sb.delete(10, 16);
// 결과: "Type Script17"
// 6. reverse(): 문자열 뒤집기 (의외로 알고리즘 풀 때 꿀팁!)
sb.reverse();
// 결과: "71tpircS epyT"
// 다시 원래대로 돌려놓기
sb.reverse(); // "Type Script17"
// 7. setCharAt(인덱스, 문자): 특정 위치의 문자 하나만 변경
sb.setCharAt(11, '8'); // '7'을 '8'로 변경
// 결과: "Type Script18"
// 8. length(): 현재 문자열의 길이 확인
int len = sb.length(); // 13
// 9. toString(): 최종적으로 String으로 변환 (출력하거나 전달할 때)
String finalResult = sb.toString();
System.out.println("최종 결과: " + finalResult);
System.out.println("총 길이: " + len);
}
}
1. toString() 메서드로 호출하는 순간, StringBuilder는 지금까지 자기가 가지고 있던 char[] 배열의 내용을 바탕으로 새로운 String 객체를 딱 하나 만들어서 반환합니다.
2. 만약 합칠 문자열이 아주 길다는 것을 미리 알고 있다면, 처음부터 크기를 지정해 성능을 고려할 수 있습니다.
// 1000글자 정도 들어갈 공간을 미리 확보 (배열 복사 과정이 생략되어 더 빠름)
StringBuilder sb = new StringBuilder(1000);