JAVA

[JAVA] String + 연산과 비효율성 StringBuilder의 해결 원리

경딩 2024. 11. 10. 20:13

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가 나왔다.

참고자료

https://www.youtube.com/watch?v=gc7bo5_bxdA

'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