TIL

24.09.05 TIL - Effective Java Item 63

개발공명 2024. 9. 8. 12:02

오늘 배운 것

  • Effective Java Item 63

6️⃣3️⃣ Item 63 : 문자열 연결은 느리니 주의하라


📌 목차

  1. 문자열 연결 방법 1
  2. 문자열 연결 방법 2
  3. 성능 차이

1️⃣ 문자열 연결 방법 1

문자열을 연결하는 방법에는 문자열 연결 연산자 (+)가 있다.

이것은 여러 문자열을 하나로 합쳐주는 편리한 수단이다.

String firstName = "minjae";
String lastName = "kim";
String name = firstName + lastName;

하지만 문자열 연결 연산자는 아래와 같은 경우에 사용해야 한다.

  1. 한 줄짜리 출력 값
  2. 작고 크기가 고정된 객체의 문자열

왜냐하면 문자열 연결 연산자를 이용해 여러 문자열을 연결하면 성능 저하가 생기기 때문이다.

문자열은 불변이라 두 문자열을 연결할 경우 양쪽의 내용을 모두 복사해야 한다.

따라서 성능 저하를 피할 수 없는 것이다.

문자열 연결 연산자로 문자열 n개를 잇는 시간은 n^2에 비례한다.


2️⃣ 문자열 연결 방법 2

성능을 포기하고 싶지 않다면 어떻게 해야 하는가?

바로 String 대신 StringBuilder를 사용하면 된다.


StringBuilder 사용법은 다음과 같다.

  1. new StringBuilder();로 StringBuilder 객체를 생성한다.
  2. .append(”~”); 메서드로 문자열을 추가한다.
  3. .toString(StringBuilder);로 String으로 바꾼다.

public String addString(){
        int num = 100;
        String str = "abcdefg";
        int len = str.length();

        StringBuilder stringbuilder = new StringBuilder(num * len);

        for(int i=0; i<num; i++){
                stringbuilder.append(str);
        }

        return stringbuilder.toString();
}

Stirng은 변경 불가능한 문자열을 생성한다.

하지만 StringBuilder는 변경 가능한 문자열을 만들어 준다.

그렇기 때문에, String을 합치는 작업 시 하나의 대안이 될 수 있다.


⏫ 성능 차이

자바 6 이후 문자열 연결 성능을 다방면으로 개선했다고 한다.

하지만 이 두 방법의 성능 차이는 여전히 크다고 하다.


길이가 80인 문자열을 100번 더했을 때 StringBuilder를 사용한 쪽이 5.5배 빨랐다고 한다.

문자열 연결 연산자를 사용하는 경우 n번 더했을 때 문자열을 연결하는 시간이 n^2이 걸린다고 했다.

StringBuilder를 사용하는 경우는 n번 더했을 때 문자열을 연결하는 시간이 n이 걸린다.

따라서 더하는 횟수가 늘어날수록 성능 격차도 더 날 것이다.


StringBuilder를 성능을 더 늘리는 방법이 있다.

바로 StringBuilder 객체를 생성할 때 전체 문자열 결과를 담기에 충분한 크기로 초기화 하는 것이다.

StringBuilder 기본으로 생성하게 되면 16글자의 String을 담을 수 있다.

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

그리고 더할 때 StringBuilder에 capacity를 확인한다.

    public AbstractStringBuilder append(String str) {
        if (str == null) {
            return appendNull();
        }
        int len = str.length();
        ensureCapacityInternal(count + len);
        putStringAt(count, str);
        count += len;
        return this;
    }

그래서 capacity가 넘치게 되면 더 큰 배열에 복사를 한다.

    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        int oldCapacity = value.length >> coder;
        if (minimumCapacity - oldCapacity > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity) << coder);
        }
    }

따라서 처음 초기화 할 때 충분한 크기로 하면 이런 과정이 필요 없기 때문에 더 성능을 개선할 수 있는 것이다.

이렇게 하면 길이가 80인 문자열을 100번 더했을 때 StringBuilder를 사용한 쪽이 6.5배 빨랐다고 한다.


'TIL' 카테고리의 다른 글

24.09.09 TIL - Bean 수동 등록  (0) 2024.09.10
24.09.06 TIL - CSRF  (0) 2024.09.08
24.09.04 TIL - Bean Validation  (0) 2024.09.08
24.09.03 TIL - Spring Security Login with JWT  (0) 2024.09.08
24.09.02 TIL - Spring Security 동작 원리  (0) 2024.09.07