Java (자바)

[Java] String / StringBuffer / StringBuilder

Oscar:) 2024. 2. 2. 19:00

 

 

이번 포스팅에서는 StringBuffer · StringBuilder에 대해 알아보겠다.

 

 

 


 

 

StringBuffer · StringBuilder 란?

 

 

문자열을 추가 · 변경할 때 사용하는 클래스이며,

객체의 값은 변경할 수 있지만 객체는 변경되지 않는 문자열을 나타낸다.

 

 

객체 불변에 대한 내용은 아래의 'String과 StringBuffer' 탭에서 자세히 다룬다.

 

일단 기본적인 사용법부터 알아보자.

 

 

 


 

사용법

 

 

기본적인 사용법은 다음과 같다.

 

// StringBuffer
StringBuffer stringBuffer = new StringBuffer();

stringBuffer.append("Oscar는 ");
stringBuffer.append("20대");

System.out.println(stringBuffer);
       
       
// StringBuilder
StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append("Harry는 ");
stringBuilder.append("30대");

System.out.println(stringBuilder);

 

 

append() 메서드를 사용하여 문자열을 더하고 출력했다.

 

 

사실 두 클래스는 큰 차이가 없다.

 

기본적인 문법과 사용법은 거의 동일하고,

StringBuffer가 조금 더 많은 메서드를 가지고 있다.

 

두 클래스에 대한 비교는 아래의 'StringBuffer와 StringBuilder 차이점' 탭에서 알아보겠다.

 

 

출력 결과는 다음과 같다.

 

 

String을 출력한 것과 다름없이 출력된다.

 


 

StringBuffer/Builder의 객체를 바로 출력할 수 있지만,

String 객체가 필요할 때는 StringBuffer/Builder .toString() 메서드로 캐스팅 해주면 된다.

 

StringBuffer stringBuffer = new StringBuffer();

stringBuffer.append("Oscar는 ");
stringBuffer.append("정말 멋져");

String str = stringBuffer.toString();
System.out.println(str);

 

StringBuffer에 문자열을 덧붙이고 String 객체에 초기화하여 출력하였다.

 

결과)

 

 

 


 

String과 StringBuffer

 

 

사실, 문자열 더하기는 아래와 같이 간단하게 할 수 있다.

 

String str = "";

str += "Oscar는 ";
str += "정말 ";
str += "멋진 것 같아.";

System.out.println(str);

 

결과)

 

 

그런데 굳이 StringBuffer · StringBuilder를 사용할 필요가 있을까?

 

위 의문을 해결하려면 String 클래스의 속성을 알아야 한다.

 


 

String은 객체 자체가 불변한다.

즉, 객체의 값이 변할 때마다 이전 객체를 버리고 새로운 객체가 생성된다고 보면 된다.

 

분명 코드상으로는 String 객체 str에 값을 계속 더해주기만 했는데,

객체가 다른 객체로 바뀐다는 것은 이해하기 어려울 수 있다.

 

 

위 예제에서 str 변수에 값을 더할 때마다

해시코드와 바이트 배열의 로그를 찍어보았다.

 

*해시코드 : 자바 응용 프로그램에서 동일한 객체를 두 번 이상 호출했을 때

객체에 대한 동등한 비교를 위해 반환되는 정수

 

String str = "";

str += "Oscar는 ";
System.out.println("(1) hashCode : " + str.hashCode());
System.out.println("(1) byteArray : " + str.getBytes() + "\n");

str += "정말 ";
System.out.println("(2) hashCode : " + str.hashCode());
System.out.println("(2) byteArray : " + str.getBytes() + "\n");

str += "멋진 것 같아.";
System.out.println("(3) hashCode : " + str.hashCode());
System.out.println("(3) byteArray : " + str.getBytes());

 

결과)

 

동일한 변수의 값이 바뀔 때마다 해시코드와 바이트 배열이 변하는 것을 확인할 수 있다.

 

 


 

 

반면, StringBuffer의 경우 객체의 값이 바뀌어도 객체가 변경되지 않는다.

 

마찬가지로,  StringBuffer에 값을 덧붙여주고 hashcode를 찍어보았다.

 

StringBuffer stringBuffer = new StringBuffer();

stringBuffer.append("Oscar는 ");
System.out.println("(1) hashCode : " + stringBuffer.hashCode());

stringBuffer.append("정말 멋진 것 같아.");
System.out.println("(2) hashCode : " + stringBuffer.hashCode());

 

결과)

 

동일한 해시코드를 출력했다.

 

 


 

 

위에서 확인했듯이, String은 값이 바뀔 때마다 매번 새로운 객체를 생성한다.

 

그렇기에 값이 바뀌는 작업이 많아지면 메모리 소모나 속도면에서 매우 불리하다.

 

 

String과 StringBuffer의 컴파일 속도를 간단히 체크해보았다.

 

String str = "";
StringBuffer stringBuffer = new StringBuffer();

System.out.println("반복문 전 : " + System.currentTimeMillis());

for (int i = 0; i < 10000; i++) {
    stringBuffer.append("A");
}

System.out.println("StringBuffer 후 : " + System.currentTimeMillis());

for (int i = 0; i < 10000; i++) {
    str += "A";
}

System.out.println("String 후 : " + System.currentTimeMillis());

 

먼저 작업 전 현재 시간을 밀리초 단위로 한 번,

StringBuffer를 for문으로 10,000번 반복 변경 후 한 번,

String을 10,000번 반복 변경 후 한 번 로그를 찍었다.

 

 

결과)

 

StringBuffer : 1m/s

String : 108m/s

 

컴파일 속도부터 100배 이상 차이가 나는 것을 확인할 수 있다.

이 차이는 더 많이 반복하면 할 수록 커질 것이다.

 

 

 


 

StringBuffer와 StringBuilder의 차이점

 

 

두 클래스는 용도도 동일하고, 사용법도 거의 비슷하다.

그래서 딱히 사용하는 기준을 정하기는 애매하다.

 

그래도 굳이 차이점을 꼽자면, 멀티 스레드 환경에서의 동기화 여부다.

 

StringBuffer의 경우 각 메서드마다 Synchronized 키워드가 존재하여,

멀티 스레드 환경에서도 동기화를 지원한다.

 

StringBuffer.java

 

 

반면, StringBuilder의 경우 멀티 스레드 환경에서는 동기화를 보장하지 않는다.

 

 

그러면 StringBuffer가 무조건 더 좋은 것 아니냐 라고 생각할 수 있는데,

 

동기화 관련 처리로 인해 StringBuilder에 비해 성능이 조금 떨어지는 것을 감안하면

단일 스레드 환경에서는 StringBuilder가 더 유리할 수 있다.

 

 

 


 

정리

 

문자열의 값이 바뀌어야 하는 상황을 다음과 같이 정리해 볼 수 있겠다.

 

 

String

문자열을 더하는 횟수가 적을 때 간편하게 사용

 

StringBuilder

멀티 스레드 환경과 관련이 없을 때 주로 사용

 

StringBuffer

멀티 스레드 환경에서 주로 사용

 

 

스레드 환경을 고려하지 않고, 단순히 성능만 비교

StringBuilder > StringBuffer >>>>> String

 

 


 

 

 

이번 포스팅에서는 StringBuffer/Builder에 대해 알아보았다.

 

StringBuffer/Builder에 대해 공부하기 전에는 매번 String으로만 값을 변경했었는데,

정말 많이 비효율적이었다는 것을 느꼈다.