[Java] 문자열 Class를 알아보자 : String / StringBuffer / StringBuilder

?에서 !로·2021년 8월 7일
0

Java

목록 보기
1/2

Java 에서 문자열을 처리하는 대표적인 클래스로 String, StirngBuffer, StringBuilder가 있습니다.

세 방식의 가장 큰 차이는 String 클래스는 Immmutable : 불변 하고 StirngBuffer, StringBuilder는 mutable : 변함 한다는 점입니다.

여기서 변한다는 것의 의미는 문자열 객체가 생성되었을 때 할당된 메모리 공간이 변하는 것에 대한 유무 입니다.

String


String은 객체가 생성되면 Heap 메모리 영역의 String Constant Pool 내부에 저장됩니다. 만약 생성된 String 객체에 변화가 생긴다면 Immutable Class이기 때문에 기존의 메모리 공간 내의 값이 변하는 것이 아니라 새로운 String 객체를 생성하여 변경된 문자열을 나타냅니다. 기존 메모리 영역은 Garbage로 남아있다가 Garbage Colloection 에 의해 사라지게 됩니다.

String str = "Back";
str += "-End";


이러한 Immutable Class 인 String장점 : 불변이기 때문에 객체에 대한 신뢰도가 높고 조회가 많은 환경이나 멀티 스레드에서 동기화 없이 객체를 공유할 수 있습니다.

하지만 단점 : 문자열에 대한 연산이 잦은 환경에서는 힙 메모리에 많은 Garbage가 생성되어 어플리케이션 성능을 저하 시킬 수 있습니다.

따라서 잦은 연산을 수행하는 환경에서는 Mutable Class인 StringBuffer / StringBuilder 을 사용하는 것이 유리합니다.

StringBuffer | StringBuilder


두 클래스는 내부 Buffer(동적 배열)에 문자열을 저장해 두고 그 안에서 데이터를 변경하는 구조로 되어 있으므로 새로운 메모리 영역의 추가 없이 기존 Buffer의 크기를 늘리며 빠르고 유연하게 문자열을 조작 가능합니다.

기본적으로 StringBuffer 와 StringBuilder동일한 API를 갖습니다. 먼저 두 Class에서 지원하는 Method 를 정리해 보겠습니다.

Method


StringBuilder str = new StringBuilder("HW");
// StringBuffer str = new StringBuffer("HW");
System.out.println(str); // HW
  • append(기본 자료형을 포함한 다양한 인자) : 문자열 추가
str.append(123);
str.append("BYE").append(456); //연이어서 사용 가능
// HW123BYE456
  • delete(int start, int end) : index start부터 (end-1)까지 삭제
str.delete(2, 5); // HWBYE456
  • insert(int offset, String str) : 문자열을 원하는 위치에 삽입
str.insert(2, 789); // HW789BYE456
  • replace(int start, int end, String str) : 원하는 부분을 다른 문자열로 대체
str.replace(5, 8, "WELCOME"); // HW789WELCOME456
  • substring(int start, (int end)) : 인자가 하나라면 해당 인덱스부터 끝까지, 두 개라면 start~(end-1)까지 인덱싱 (반환 타입은 String 인스턴스)
System.out.println(str.substring(5)); // WELCOME456
  • reverse() : 저장된 문자열을 뒤집어 줍니다.
str.reverse(); // 654EMOCLEW987WH

그렇다면 둘의 차이점은 무엇일까요?

바로 동기화(Synchronized) 여부입니다. StringBuffer는 각 Method 별로 동기화 키워드를 지원하여 멀티쓰레드 환경에서 안전성을 보장합니다. 반면, StringBuilder은 동기화를 보장하지 않습니다.
(위에서 소개했듯이 String Class도 Immutable 하기에 멀티쓰레드 환경에서 안전성을 보장합니다.)

다음의 Append Method 구현을 통해 동기화 여부를 확인해 보았습니다.

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

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

하지만 단일쓰레드 환경에서는 동기화 처리 과정이 없는 StringBuilder가 더 좋은 성능을 보입니다.
정리하자면, 일반적으로는 각각 다음과 같은 경우에 사용하는 것이 유리하다 할 수 있습니다.

String : 문자열 연산이 적거나 단일스레드 환경
StringBuffer : 문자열 연산이 많거나 멀티쓰레드 환경일 경우
StringBuilder : 문자열 연산이 많거나 단일쓰레드 또는 동기화를 고려하지 않아도 되는 환경

  • 추가적으로 JDK 1.5 버전 이후부터 String의 + 연산은 컴파일 단계에서 StringBuilder로 자동 변환되었습니다. 하지만 반복문에서 사용 시 StringBuilder 객체를 계속 추가하므로 성능이 좋지 않습니다. 즉, 한줄로 선언하는 경우에는 사용해도 될 것 같습니다.
    ex) String str = "B" + "Y" + "E";

0개의 댓글