String에 + 연산은 상수풀에 메모리가 할당되어 중간연산 과정에서 많은 객체를 생성한다. StringBuilider를 사용하면 중간과정의 비효율을 해결할 수 있다는데 어떠한 원리로 해결하였을까?
궁금증이 생겨 해당 내용을 포스팅하게 되었다.
String에서 + 연산과 그 비효율성
String 객체에서 + 연산을 사용할 때마다 새로운 객체가 생성된다. 이는 불변 (immutable) 특성 때문에 발생하는데 , String 객체는 한번 생성되면 그 값을 변경할 수 없다.
따라서 + 연산을 통해 여러 문자열을 이어 붙일 때, 중간 과정에서 새로운 String 객체들이 계속 생성되고, 이 객체들은 상수 풀에 할당되어 메모리를 추가로 차지한게 된다. 이로 인해 불필요한 객체가 계속해서 생성되고 메모리 사용과 성능에 부담을 주게 된다.
StringBuilider를 사용하면 중간과정의 비효율을 해결할 수 있다는데 어떠한 원리로 해결하였을까?
StringBuilder는 가변(mutable) 객체로, 문자열을 수정할 때마다 새로운 객체를 생성하는 것이 아니라 내부적으로 배열을 사용해 문자열을 관리한다.
이 배열은 크기가 동적으로 확장되며, 문자열을 이어 붙일 때마다 배열의 크기를 재조정하여 추가적인 객체 생성 없이 문자열을 처리할 수 있다.
StringBuilder 는 초기 배열 크기를 설정하고, 추가적인 문자가 들어오면 이 배열의 크기를 조정한다. 이렇게 하면 중간에 불필요한 객체 생성이 없고 메모리 사용도 효율적으로 관리된다. 즉 문자열을 여러 번 변경할 때마다 발생하는 중간연산과정의 비효율성을 해결할 수 있다.
StringBuiler의 코드를 확인해 보자
class StringBuilder {
private char[] value; // 문자열을 저장할 char 배열선언
private int size; // 배열방의 크기
private int index; // 새로 추가될 character 의 방 번호
StringBuilder () {
// 객체 초기화 작업
size = 1;
value = new char[size];
index = 0;
}
public void append(String str) {
// 문자열을 추가하는 함수
if (str == null) str = "null";
int length = str.length();
ensureCapacity(length); // 문자열이 담기에 크기가 충분한지 확인 , 부족하면 늘리기
for (int i = 0; i < str.length(); i++) {
value[index] = str.charAt(i);
index++;
}
System.out.println("size : " + size + " , index : " + index);
}
public void ensureCapacity(int length){ // 배열 방 크기 확보
if( index + length > size ) { // 현재 인덱스 + 문자열의 크기 가 현재 배열방 크기를 초과할 경우
size = (size + length) * 2; // 현재 방크기 + 문자열 * 2
char[] newValue = new char[size];
for (int i = 0; i < value.length; i++) {
newValue[i] = value[i]; // 기존 배열들은 돌면서 새로운 배열에 복사하기 - 문자열이므로 데이터가 아닌 포인터를 복사하는 거임
}
value = newValue;
}
}
public String toString(){ // 현재 저장된 배열방의 0번방부터 index까지 모든 character 를 문자열로 변환하여 반환
return new String(value, 0, index);
}
}
public class Test {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("sung");
sb.append(" is");
sb.append(" pretty");
System.out.println(sb.toString());
}
}
실행결과
- 초기 사이즈는 (1 + 4)*2를 해서 10 , [sung]을 추가하여 index는 4가 나왔다.
- 후에 [ is]는 배열 방이 넉넉함으로 size 10 index는 [ is] 추가하여 index 는 7이 나왔다.
- 후에 [ pretty]를 추가하여 (10+ 7)*2 size 34 index는 14가 나왔다.
참고자료
'JAVA' 카테고리의 다른 글
[JAVA] 데몬 스레드 (0) | 2024.11.11 |
---|---|
[JAVA] 스레드란? run() start() 의 차이 (0) | 2024.11.11 |
[JAVA] 제네릭 (Generic) (0) | 2024.11.08 |
[자바의 신2] 정리해봅시다 [2장~ 11장] (0) | 2024.11.07 |
[JAVA] Grabage Collection Basics (0) | 2024.11.05 |