Home Item63 (문자열 연결은 느리니 주의하라)
Post
Cancel

Item63 (문자열 연결은 느리니 주의하라)

문자열 연결은 느리니 주의하라

문자열을 연결할 때 단순히 ‘+’를 사용해 아주 쉽게 여러 문자열을 하나로 합칠 수 있다.

하지만 한 줄 짜리 출력값 혹은 작고 크기가 고정된 객체의 문자열 표현을 만드는 정도라면 괜찮지만, 본격적으로 사용하게 된다면 성능 저하를 감내하기 어렵다.

문자열 연결 연산자로 문자열 n개를 잇는 시간은 n^2에 비례한다. 문자열은 불변이기 때문에 두 문자열을 연결할 경우 양쪽의 내용을 모두 복사해야해 성능 저하가 필연적이다.

문자열 연결 연산자 성능

1
2
3
4
5
6
7
public String statement() {
	String result = "";
	for (int i = 0; i < 100_000; i++) {
		result += "abc"
	}
	return result;
}
  • 함수가 실행되는데 3.43초가 걸렸다. 수가 더 커진다면 심각하게 느려질 것이다.

그렇다면 StringBuilder를 사용하면 어떻게 될까?

1
2
3
4
5
6
7
public String statement() {
	StringBuilder b = new StringBuilder();
	for (int i = 0; i < 100_000; i++) {
		b.append("abc");
	}
	return b.toString;
}
  • 1초도 걸리지 않는다.
  • Java 6 이후 문자열 연결에 대한 성능을 다방면으로 개선했지만, 두 메서드의 성능 차이는 보다시피 매우 크다.
  • StringBuilder는 String과 다르게 가변이다. 이 부분에서 내부 동작의 차이가 발생해 성능 차이가 발생한다.
  • String
    • 현재 문자열과 새로 추가할 문자열의 길이를 더한 새로운 배열을 생성한다.
    • 현재 String 객체의 내용을 배열에 복사하고, 추가할 문자열 또한 배열에 복사한다.
    • 새로운 배열을 기반으로 새로운 String 객체를 생성한다.
    • 이 과정을 거치면서 매우 많은 객체가 생성되게 된다.
  • StringBuilder
    • 초기 용량을 가진 배열을 생성한다.
    • 문자열을 추가할 때 배열의 남은 공간을 확인하고 남은 공간이 충분하면 추가할 문자열을 배열에 복사한다.
    • 남은 공간이 부족하다면 현재 배열의 크기를 늘리고 기존 배열의 내용을 새로운 배열에 복사하고, 추가할 문자열을 복사한다.
    • 위와 같은 과정으로 비교적 객체의 생성과 메모리 할당이 적게 발생해 성능 차이가 크게 나는 것이다.

정리

성능에 신경써야 하는 경우, 많은 문자열을 연결할 때 문자열 연결 연산자를 사용하지 말고 StringBuilder를 사용하자.

String은 불변이라는 사실을 잊으면 안된다.

문자 배열을 사용하거나, 문자열을 연결하지 않고 하나씩 처리하는 방법도 있다.

This post is licensed under CC BY 4.0 by the author.

Item62 (다른 타입이 적절하다면 문자열 사용을 피하라)

Item64 (객체는 인터페이스를 사용해 참조하라)