우선 크게 String과 StringBuffer & StringBuilder로 차이점을 확인 해보자.
String & StringBuilder & StringBuffer 비교
1). String vs StringBuilder & StringBuffer 차이점
String : 객체는 한번 생성되면 할당된 공간이 변하지 않음(immutable)
StringBuffer & StringBuilder : 객체의 공간이 부족해지는 경우 버퍼의 크기를 유연하게 늘려줍니다. (mutable)
메모리 관점으로 설명을 추가해보자면...
String은 Immutable하기 때문에 메모리상에 추가적인 공간을 할당받아야한다
예를 들어 , hello를 메모리에 올리고, world를 추가해서 이어붙이려고한다.
이때 메모리상에서는 Heap의 stringpool에 hello가 적재되고, 변수 str 은 hello를 바라보게된다.
추가로 world를 붙이게 될때 str이 바라보던 기존 hello를 바라보지 않고, 새로운 helloworld라는 데이터를 적재하게된다.
이때 그럼 기존의 hello는 어떻게 되는것인가? => str이 바라보는것을 중지하고, str은 helloworld를 바라보며, str이 바라보는것이 중지된 hello는 gc에 의해 삭제목록으로 들어가게 된다.
이로써 문자열이 계속 변경 되어야 할 경우 String 보다는 String Buffer를 사용하는것이 좋다.
그렇다면 StringBuffer와 StringBuilder의 차이점은 어떤것이 있을까라는 생각을 하게 된다.
StringBuilder와 StringBuffer의 차이점을 확인 해보자.
2). StringBuffer vs StringBuilder 차이점 ==>동기화(Syncronized) 지원 유무!!!
StringBuffer : 각 메서드별 sysnchronized keyword가 존재하여 Multi-Thread 상태에서 동기화를 지원한다.
StringBuilder : Single-Thread환경에서만 사용하도록 만들어졌다. StringBuffer보다 속도는 빠름
StringBuffer와 StringBuilder를 사용하면 좋은 경우
String str = "hello";
str+= "world";
위와 같은 경우 String은 크기가 고정되어있기 때문에 문자열을 수정할 수 없다. 결국 매번 새로운 String 객체를 생성해서 문자열을 할당한다고 보면 된다.
당연히 메모리상 불필요한 공간을 많이 사용하고, 속도는 더 느려질 수 밖에없다.
하지만 StringBuffer 와 StringBuilder는 매번 new를 하지 않고 , 추가/수정/삭제 기능을 수행할 수 있도록 설계되어있어 새로운 객체를 생성하지 않아도 된다.
당연히 매번 새로운 객체를 만드는것보다 훨씬 성능은 좋을수 밖에 없다.
하지만 !!!!! 여기서 그럼 당연히 StringBuffer만 쓰면 땡이네 라고 할 수 있다.
여기서 간과하면 안돼는 점이 있다.
StringBuffer나 StringBuilder의 단점이 한가지 있다.
바로 StringBuffer나 StringBuilder를 생성할때 Buffer의 크기를 초기에 설정 해줘야하는데, 이 때문에 객체 생성속도는 느려진다.
그러므로 많은연산이 일어나는경우가 아니면 String을 사용해서 문자열 연산을 하는것이 나을수 있다.
시간 비교
public class testMain {
public static double longStr(int len) {
long start = System.nanoTime();
String str = "";
for(int i=0 ; i < len ; i++) {
str += "a";
};
long end = System.nanoTime();
return (end-start)/(double)1_000_000_000;
}
public static double longStrBuffer(int len) {
long start = System.nanoTime();
StringBuffer sb = new StringBuffer();
for(int i=0 ; i < len ; i++) {
sb.append("a");
};
long end = System.nanoTime();
return (end-start)/(double)1_000_000_000;
}
public static double longStrBuilder(int len) {
long start = System.nanoTime();
StringBuilder sb = new StringBuilder();
for(int i=0 ; i < len ; i++) {
sb.append("a");
};
long end = System.nanoTime();
return (end-start)/(double)1_000_000_000;
}
public static void main(String[] args) {
int[] lenList = new int[]{10_000, 20_000, 40_000, 80_000, 160_000, 320_000, 640_000,
1_280_000, 2_560_000, 5_120_000, 10_240_000, 20_480_000, 40_960_000, 81_920_000, 163_840_000};
for(int len : lenList)
{
System.out.println("String :\t" + len + "/\t" + longStr(len));
System.out.println("StringBuffer :\t" + len + "/\t" + longStrBuffer(len));
System.out.println("StringBuilder :\t" + len + "/\t" + longStrBuilder(len));
}
}
}
String : 10000/ 0.0521221
StringBuffer : 10000/ 7.252E-4
StringBuilder : 10000/ 3.549E-4
String : 20000/ 0.1562421
StringBuffer : 20000/ 8.992E-4
StringBuilder : 20000/ 4.286E-4
String : 40000/ 0.5575475
StringBuffer : 40000/ 0.0017252
StringBuilder : 40000/ 0.0011155
String : 80000/ 1.6480827
StringBuffer : 80000/ 0.0029146
StringBuilder : 80000/ 0.0037118
String : 160000/ 6.5718681
StringBuffer : 160000/ 0.0027307
StringBuilder : 160000/ 0.0019174
String : 320000/ 30.3206881
StringBuffer : 320000/ 0.003266
StringBuilder : 320000/ 0.0031393
String : 640000/ 135.6962307
StringBuffer : 640000/ 0.0045165
StringBuilder : 640000/ 0.0057316
String : 1280000/ 568.2966798
StringBuffer : 1280000/ 0.0082649
StringBuilder : 1280000/ 0.0098229
160000부터 String때문에 너무 느려져서 그이상은 버티다 버티다 포기했다.
이정도로 많은 연산을 필요로 할 상황이 아니면... String이 좋지만
이정도로 많은 연산을 해야하면 String은 절대 쓰면 안됀다는것을 확인 할 수 있다.
'Java > Basic' 카테고리의 다른 글
[Java] Builder Pattern이란? 객체 생성 방법들 (0) | 2021.03.19 |
---|---|
[Java-Basic] 재귀함수를 통해 팩토리얼 연습 (0) | 2021.02.15 |
[Java] Collection 정리 Map이란 HashMap & TreeMap (0) | 2021.01.28 |
[Java] Collection 정리 List란 ArrayList & LinkedList (0) | 2021.01.28 |
[Java-Basic] Reflection API 를 사용하여 Custom Annotation 만들기 (0) | 2021.01.22 |