문자열 연결 연산자(+)는 여러 문자열을 하나로 합쳐주는 편리한 수단이다. 하지만 문자열 연결 연산자로 문자열 n개를 잇는 시간은 n^2에 비례한다. 그런데 한 줄짜리 출력값 혹은 작고 크기가 고정된 객체의 문자열 표현을 만들때라면 괜찮지만, 본격적으로 사용하기 시작하면 성능 저하를 감내하기 어렵다. 문자열은 불변이라서 두 문자열을 연결할 경우 양쪽의 내용을 모두 복사해야 하므로 성능 저하는 피할 수 없는 결과다.
다음은 청구서의 품목(item)을 전부 하나의 문자열로 연결해주는 메소드다.
1 2 3 4 5 6 7 | // 문자열 연결을 잘못 사용한 예 - 느리다! public String statement() { String result = ""; for (int i = 0; i< numItems(); i++) result += lineForItems(i); // 문자열 연결 return result; } | cs |
품목이 많을 경우 이 메소드는 심각하게 느려질 수 있다. 성능을 포기하고 싶지 않다면 String 대신 StringBuilder를 사용하자.
1 2 3 4 5 6 7 | // StringBuilder를 사용하면 문자열 연결 성능이 크게 개선된다. public String statement2() { StringBuilder b = new StringBuilder(numItems() * LINE_WIDTH); for (int i = 0; i < numItems(); i++) b.append(lineForItems(i)); return b.toString(); } | cs |
자바 6 이후 문자열 연결 성능을 다방면으로 개선했지만, 위의 두 메소드의 성능 차이는 여전히 크다. statement 메소드의 수행 시간은 품목 수의 제곱에 비례해 늘어나고, statement2 메소드는 선형으로 늘어나므로, 품목 수가 늘어날수록 성능 격차도 점점 벌어질 것이다. statement2에서 StringBuilder를 전체 결과를 담기에 충분한 크기로 초기화한 점을 잊지 말자.
원칙은 간단하다. 성능에 신경 써야 한다면 많은 문자열을 연결할 때는 문자열 연결 연산자(+)를 피하자. 대신 StringBuilder의 append 메소드를 사용하라. 문자 배열을 사용하거나, 문자열을 연결하지 않고 하나씩 처리하는 방법도 있다.