String
-짧은 문자열을 더할 경우에만 사용하자.
-왠만하면 사용을 지양하자(생성할수록 무한대로 새로운 주소값이 생성되기때문).
StringBuffer
-스레드에 안전한 프로그램 또는 개발중 스레드에 안전을 장담할수 없을때 사용하자
StringBuilder
-스레드에 안전여부와는 전혀관계없는 프로그램 개발시 사용하자.
간단한 성능테스트를 위해 jmh(Java Microbenchmark Harness) 를 사용하였다.
정해진 문자열을 지속적으로 더해서 새로운 문자열을 만드는 테스트 진행
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.19</version>
</dependency>
jmh 공식 MD 에서는 아래의 구조와 같게 구성할것을 권고하고 있다.
src/jmh
구조에 맞게 구성하자
https://github.com/melix/jmh-gradle-plugin#configuration
package test;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
@BenchmarkMode({Mode.AverageTime})
@OutputTimeUnit(TimeUnit.MICROSECONDS) //밀리세컨드 단위로 출력
@Fork(value = 2, jvmArgs= {"-Xms4G", "-Xmx4G"})//측정을 한번만 하는것은 벤치마크의 신뢰성에 문제가 있을 수 있다.
// 특정 시점에 시스템이 다른 이유로 갑자기 느려지거나 하는 상황이 있을 수 있기 때문에 최대한 외부 변수의 영향을 배제하기 위해 측정을 2회 실시한다.
//그리고 힙 영역의 공간 부족으로 인한 gc 오버헤드를 최소화 하기 위해 힙 영역의 크기를 4GB 로 설정한다.
public class BenchTest {
static final String aValue = "abc";
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(BenchTest.class.getSimpleName())
.forks(2)
.build();
new Runner(opt).run();
}
@Benchmark
public static String makeString(){
String a = new String();
for (int inLoop = 0; inLoop<10000; inLoop++){
a+=aValue;
}
return a;
}
@Benchmark
public static String makeStringBuffer(){
StringBuffer sf = new StringBuffer();
for (int inLoop = 0; inLoop<10000; inLoop++){
sf.append(aValue);
}
return sf.toString();
}
@Benchmark
public static String makeStringBuilder(){
StringBuilder sb = new StringBuilder();
for (int inLoop = 0; inLoop<10000; inLoop++){
sb.append(aValue);
}
return sb.toString();
}
}
스레드를 고려하지 않은 테스트 환경에서는 StringBuilder 가 가장 효율적이라는 것을 확인 할 수 있구만
TMI
WAS나 시스템이 JDK5.0 이상을 사용한다면, 컴파일러에서 자동으로 StringBuilder로 변환해준다.