Skip to content

Latest commit

 

History

History
115 lines (85 loc) · 4.24 KB

63_문자열_연결은_느리니_주의하라_김세윤.md

File metadata and controls

115 lines (85 loc) · 4.24 KB

아이템 63. 문자열 연결은 느리니 주의하라

문자열 연결 연산자

  • + 를 이용해 문자열을 연결하면 굉장히 편리하긴 하다.
  • 그러나 가장 큰 단점이 있다. 바로 문자열 연결 연산자로 문자열 N개를 잇는 시간은 N^2에 비례한다는 것이다.
  • 즉, 엄청나게 느리다는 뜻이다.
  • 그 이유는 문자열(String)은 불변이다. 불변인 문자열을 연결하기 위해서는 양쪽의 내용을 복사해 새로운 문자열을 만들어야 하기 때문이다.

StringBuilder vs StringBuffer

  • String은 불변이기 때문에 가변을 지원하는 StringBuilder와 StringBuffer를 제공해준다.

StringBuilder

  • 빌더패턴을 이용해 String을 처리한다고 생각하면 좋을거 같습니다.(그러나 해당 StringBuilder가 빌더 패턴을 사용한거지에 대한 논란은 있습니다.)
  • StringBuffer에 비해 Thread-Safe 하지 않지만, 싱글쓰레드 환경에서는 연산처리가 굉장히 빠르다.

StringBuffer

  • StringBuilder와 기능을 똑같지만, 멀티쓰레드 환경을 고려해 synchronized 키워드를 사용해 동기화를 할 수 있다. 즉, Thread-Safe한 객체이다.

cf) String.join

public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        // Number of elements not likely worth Arrays.stream overhead.
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }
  • StringJoiner를 사용하는데 아래 코드와 같이 구획문자(Delimiter), prefix와 Suffix가 있다.
  • StringBuilder와 비슷하게 동작하지만, 구분자 넣는 기능이 추가되었다고 생각하면 된다.

예시

  • 아래는 프로그래머스의 코딩 테스트 문제입니다.

image

  • 한번 이문제를 문자열 연결 연산자로 return값을 구해보려고 합니다.
import java.util.Arrays;
import java.util.Collections;

class Solution {
    public String solution(String s) {
        String[] sArray = s.split("");
        Arrays.sort(sArray, Collections.reverseOrder());
        String answer = "";
        for (String sValue : sArray){
            answer += sValue;
        }
        return answer;
    }
}
  • 현재 sort를 한 이후 문자열 연산자로 하나씩 값을 더해주고 있습니다. 이때 과연 속도는 얼마나 나올까요?

image

  • 실제 생각한 이상으로 느리진 않다고 생각할 수 있다.
  • 그렇다면 StringBuilder는 얼마나 나올까?
import java.util.Arrays;
import java.util.Collections;

class Solution {
    public String solution(String s) {
        String[] sArray = s.split("");
        Arrays.sort(sArray, Collections.reverseOrder());
        StringBuilder stringBuilder =new StringBuilder();
        for (String sValue : sArray){
            stringBuilder.append(sValue);
        }
        return stringBuilder.toString();
    }
}

image

  • 확연히 속도가 빠른걸 확인할 수 있다.
  • 현재같은 경우는 길이를 따로 정하진 않았지만(기본값을 사용), 좀 더 성능을 생각하기 위해 길이를 지정한다면, 최대한 여유롭게 초기화를 해야 한다.
  • 배열이라는 조건에서 String.join() 을 사용하면 어떨까?
import java.util.Arrays;
import java.util.Collections;

class Solution {
    public String solution(String s) {
        String[] sArray = s.split("");
        Arrays.sort(sArray, Collections.reverseOrder());
        return String.join("", sArray);
    }
}

image

  • StringBuilder와 비슷한걸 볼수 있다.

결론

  • 많은 문자열을 연결할 때는 문자열 연결 연산자(+)가 아닌 StringBuilder를 사용하라.