제리 devlog

[이펙티브 자바] 문자열 연결은 느리니 주의하라 + 문자열 연결 방법 비교 본문

Java

[이펙티브 자바] 문자열 연결은 느리니 주의하라 + 문자열 연결 방법 비교

제리 . 2020. 11. 22. 15:08

+ 연산으로 계산한 경우

 

10만개의 "abcd"를  붙였다.

public static void main(String[] args){
    long startTime = System.currentTimeMillis();
    String result = "";
    for(int i=0; i<100000; i++){
      result += "abcd";
    }
    long endTime = System.currentTimeMillis();
    System.out.println("걸린 시간 : " + (float)(endTime-startTime)/1000 + "초");
  }

 

문자열 연결 연산자로 문자열n개를 잇는 시간은 n^2에 비례한다. 문자열은 immutable해서 두 문자열을 연결할 경우 양쪽 내용을 모두 복사해야한다.

 

StringBuilder를 사용한 경우

 

10만개의 "abcd"를  붙였다.

 public static void main(String[] args){
    long startTime = System.currentTimeMillis();
    StringBuilder builder = new StringBuilder(4 * 100000);
    for(int i=0; i<100000; i++){
      builder.append("abcd");
    }
    String result = builder.toString();
    long endTime = System.currentTimeMillis();
    System.out.println("걸린 시간 : " + (float)(endTime-startTime)/1000 + "초");
  }

 

용량 설정을 입력 수와 달리하고  500만개의 "abcd"를  붙였다.

public static void main(String[] args){
   
    ..
    
    StringBuilder builder = new StringBuilder(4 * 100000);
    for(int i=0; i<5000000; i++){
      builder.append("abcd");
    }
   
    ..
  }

 

용량 설정을 입력 수와 맞추고  500만개의 "abcd"를  붙였다.

public static void main(String[] args){
    ..
    
    StringBuilder builder = new StringBuilder(4 * 5000000);
    for(int i=0; i<5000000; i++){
      builder.append("abcd");
    }
    
    ..
  }

 

append과정에서 확인하고 용량이 부족하면 용량을 입력받은 String의 길이만큼 더 추가한다. 매번 이 작업이 이뤄지기 때문에 초기 용량 값 설정이 속도에 영향을 준다.

 

concat을 사용한 경우

10만개의 "abcd"를  붙였다.

public static void main(String[] args){
    
    ..
    
    String result = "";
    for(int i=0; i<100000; i++){
      result = result.concat("abcd");
    }
    
    ..
  }

concat과 StringBuilder의 차이점은 concat은 매번 새로운 String 객체를 만들고 StringBuilder는 append로 char array를 만들었다가 toString메서드 호출시 String객체를 만든다.

 

StringBuffer를 사용한 경우

 

10만개의 "abcd"를  붙였다.

public static void main(String[] args){
	..
    
	StringBuffer sb = new StringBuffer(4* 100000);
    for(int i=0; i<100000; i++){
      sb.append("abcd");
    }
    String result = sb.toString();
    
    ..
  }

 

용량 설정을 입력 수와 달리하고  500만개의 "abcd"를  붙였다.

 

public static void main(String[] args){
	..
    
    StringBuffer sb = new StringBuffer(4* 100000);
    for(int i=0; i<5000000; i++){
      sb.append("abcd");
    }
    String result = sb.toString();
    
    ..
  }

 

용량 설정을 입력 수 같게하고 500만개의 "abcd"를  붙였다.

public static void main(String[] args){
	..
    
    StringBuffer sb = new StringBuffer(4* 5000000);
    for(int i=0; i<5000000; i++){
      sb.append("abcd");
    }
    String result = sb.toString();
    
    ..
  }

 

 

StringBuffer의 append도 타고가보면 StringBuilder와 같은 메서드를 사용한다.

 

 

비교 결과 : StringBuilder > StringBuffer > concat >> +연산

 

실제 벤치 마크를 비교해보자.

StringBuilder와 StringBuffer가 유사하고 그다음으로 concat과 +연산 순서였다.

 

StringBuilder와 StringBuffer중 어떤걸 써야하나?

둘다 append시 같은 메서드를 사용하고 있었다. 그렇다면 어떤 차이가 있을까?

 

둘의 차이는 synchronized에 있다. thread safe하게 보장하는지 아닌지가 다른 것이다.

synchronized키워드르 사용해서 동기화를 하게되면 block unblock 처리하게 되는데 이런 처리로 인해 프로그램 성능이 저하될 수 있다.

 

단일 스레드 환경에서는 StringBuilder, 멀티 스레드 환경에서는 StringBuffer가 적합하다.

Comments