String, String Buffer vs String Builder

박건희·2021년 8월 3일
0

Java

목록 보기
1/2

1. String Class

  • String은 reference Type으로 String 객체가 메모리에 저장된 주소를 저장한다.
  • immutable 객체이다 : 문자열을 변경할 수 없다, Read-Only
// String 클래스에서 문자열을 저장하는 배열
 private final byte[] value;   

 -> 'final' 키워드로 value 배열을 선언해서 값을 바꾸지 못한다.
  • 문자열 비교는 equals(String str) 메소드를 사용한다.
    == 연산자는 레퍼런스 비교(String 참조변수가 reference를 저장하기 때문)

  • String literal과 String Object는 조금 다른 특성이 있는데 String literal은 먼저 자세히 보자.

    • String literal은 String Constant Pool이라는 영역에서 다룬다. 한번 할당된 literal을 다른 참조변수가 reference하면 같은 literal을 reference한다.

    • String Object는 Heap영역에 할당되고, 생성자 호출시마다 Heap의 다른 영역에 할당된다.

      위 차이는 아래 코드로 설명된다.

public class Main {
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "Hello";
        String s3 = new String("Hello");

        System.out.println(s1==s2);        //true
        System.out.println(s1.equals(s2)); //true

        System.out.println(s1==s3);        //false
        System.out.println(s1.equals(s3)); //true
    }
}

String 추가자료 : String literal/Object를 인스턴스 변수로 갖는 Class의 인스턴스의 ==와 equals()를 잘 설명하는 글.

알아볼 것

  • 예전자료를 보면 String이 char[]을 사용한다고 나와있는데 내 환경(Open JDK-16)에선 byte[]를 사용하고 있다.
  • 자바에서의 reference와 주소의 의미

2. String Builder, Buffer

  • 공통점 : 내용(문자열) 변경 가능, 문자열 비교(.toString() 후 equals()로)
 StringBuffer sb = new StringBuffer("Hello");
 sb.append("w").append("orld"); // append()로 문자열을 덧붙일 수 있음.

** 위의 StringBuffer는 StringBuilder로 치환 가능(동일 API 지원)

  • 주요 API

    메소드기능
    append(Arg a)String Buffer sequence 뒤에 a를 string representation형태로 덧붙임a는 primitive(byte, short제외), String, String Buffer, Object Class 등 가능
    insert(int offset, Arg a)a를 String Buffer의 offset 위치에 덧붙임
    replace(int start, int end, String str)start, end가 지정하는 substring을 str로 대체
  • 문자열 비교 : java.lang.Object의 equals()를 overriding 하지 않음. ==도 레퍼런스 비교.
    -> toString()으로 String으로 변환하여 equals()로 비교한다.

  • 차이점 : synchronized 지원 여부

    StringBuffer는 synchronized 를 지원하여 멀티쓰레드 환경에서 thread-safe 하다.
    ** String은 immutable이라 마찬가지로 멀티쓰레드 환경에서 thread-safe 하다.

    @Override
    @IntrinsicCandidate
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

반대로 StringBuilder는 synchronized 를 지원하지 않기때문에 멀티쓰레드 환경에서 thread-unsafe이지만 동기화를 고려하지 않는 만큼 단일쓰레드에서의 성능은 StringBuffer 보다 좋다.

   @Override
   @IntrinsicCandidate
   public StringBuilder append(String str) {
       super.append(str);
       return this;
   }
   

append의 parameter로는 다양한 type이 가능하다(String과 마찬가지로 byte로 변환하여 저장하기 때문?)

String Buffer와 Builder의 성능차이

StringBuffer buffer = new StringBuffer();
StringBuilder builder = new StringBuilder();

for (int i = 0; i < 20000000; i++) {
    buffer.append("Hello").append(" World").append(" Java").append(" Programming");
}     // 903ms

for (int i = 0; i < 20000000; i++) {
    builder.append("Hello").append(" World").append(" Java").append(" Programming");
}     // 1064 ms

위 실험(2000만회 반복)결과 약 1.06초의 성능차를 확인했다.
append할 문자열이 길 수록, 반복이 많을 수록 그 차이가 많이 날 것이다.

3. 사용예

  • StringBuilder
    Spring의 FilterChainProxy의 filter중 DefaultLoginPageGeneratingFilter
    Spring MVC는 ThreadPerRequest모델을 기본으로 채택하므로 동기화를 고려하지 않아도 됨

4. 정리

  • 사용 환경
    String : 문자열 연산이 적고 멀티쓰레드 환경일 경우
    StringBuffer : 문자열 연산이 많고 멀티쓰레드 환경일 경우
    StringBuilder : 문자열 연산이 많고 단일쓰레드이거나 동기화를 고려하지 않아도 되는 경우
StringStringBufferStringBuilder
저장공간Constant String PoolHeapHeap
변경불가가능가능
Thread-safe(Synchronized)OOX
성능빠름느림빠름

0개의 댓글