Java/Java 를 파헤쳐보자

[JAVA 파헤쳐보기] String / StringBuffer / StringBuilder

동구름이 2023. 2. 17. 23:22

 Java를 사용해 알고리즘 문제를 풀다가, StringBuffer와 StringBuilder의 사용법도, 내장 메서드도 비슷한데 왜 두 가지로 나뉘어져 있는가에 대한 의문이 들었습니다. 그렇게 찾아보니 String과의 차이도 중요하다는 것을 알았습니다.

 

 이번 포스팅에서는 세 가지 자료형에 대한 성능과 차이를 공부한 것을 정리하겠습니다.

 

 

1. String  과  StringBuffer / StringBuilder 비교

String

 우선 StringBuilder와 StringBuffer는 주로 문자열을 이어붙일 때 주로 사용합니다. 하지만, String만으로도 concat() 또는 "+" 연산을 통해 문자열을 이어 붙일 수 있습니다.

 

 굳이 String이 아닌 StringBuilder와 StringBuffer를 사용하는 이유가 무엇일까요?

 바로 String을 통해 문자열을 결합하게 되면, 공간의 낭비와 성능이 매우 느려지기 때문입니다. 이유는 String 객체가 불변 자료형이기 때문입니다.

 

실제 String 객체의 내부를 들여다보면, 아래처럼 value 변수가 final로 선언된 것을 볼 수 있습니다.

 여기서 value 값이 인스턴스 생성시에 생성자의 매개변수로 입력받는 문자열 입니다. 이 value라는 변수가 final이기 때문에 값을 바꿀 수 없습니다.

 

 그런데 String 객체에 concat() 또는 "+"를 이용해 값을 변환하는 것은 어떻게 가능할까요? 이것은 값을 변환하는 것이 아니라, 새로운 값을 업데이트하는 것입니다.

 문자열을 합치는 것 뿐만 아니라, String 의 값을 변환시키는 trim 등의 메서드는 문자열 자체를 변경하는 것이 아니라, 새로운 String 객체를 생성해 업데이트하는 것입니다.

 

이렇게 String 은 문자열을 결합하면 결합할수록, 공간의 낭비 뿐 아니라 속도가 매우 느려지게 되는 단점이 있습니다.

 

 

 

StringBuffer / StringBuilder

반면 StringBuffer 와 StringBuilder는 가변적입니다. 

 

 

 자바 코드를 열어보면 StringBuffer 와 StringBuilder는 모두 AbstractStringBuilder를 extends하는 것을 알 수 있습니다.

 

 

그리고 AbstractStringBuilder는 final 선언이 되어있지 않는 가변적인 구조라는 것을 알 수 있습니다.

 

 두 클래스를 들여다보면 데이터를 임시로 저장하는 buffer를 통해 문자열을 저장하고, 그 안에서 문자열 변환 작업을 할 수 있도록 되어있습니다.

 

 그렇기 때문에 String과는 달리, 문자열 연산시에 동일 객체 내에서 문자열이 변경될 수 있습니다.

 

 그러므로, String에 비해 공간 낭비가 없고, 새로운 인스턴스를 만드는 String과 달리 속도가 빠르다는 강점이 있습니다.

 

 

String.concat(), StringBuffer, StringBuilder 성능 비교

그래서, String.concat() 과 StringBuffer, StringBuilder의 성능은 아래처럼 확연한 차이가 나는 것을 볼 수 있습니다.

 

 

 

 

2. StringBuffer와 StringBuilder 비교

 StringBuffer와 StringBuilder 클래스는 둘 다 크기가 가변적으로 변하고, 제공하는 메서드도 동일합니다. 한 가지 다른 것은 멀티 스레드 환경에서 안전한가, 안전하지 않은가 입니다.

 

 결론부터 말하면 StringBuffer 클래스는 스레드에서 안전(thread safe)하고, StringBuilder 클래스는 스레드에서 안전하지 않습니다 (thread unsafe).

 

 StringBuffer는 메서드에서 synchronized 키워드를 사용하기 때문에, 동기화를 지원해 멀티 스레드에서 안전하게 동작할 수 있습니다.

 

아래는 다른 포스팅에서 참고한 코드입니다.

//출처 : https://inpa.tistory.com/entry/JAVA-String-StringBuffer-StringBuilder차이점성능비교


import java.util.*;

public class Main extends Thread{
  public static void main(String[] args) {
    StringBuffer stringBuffer = new StringBuffer();
    StringBuilder stringBuilder = new StringBuilder();

    new Thread(() -> {
        for(int i=0; i<10000; i++) {
            stringBuffer.append(1);
            stringBuilder.append(1);
        }
    }).start();

    new Thread(() -> {
        for(int i=0; i<10000; i++) {
            stringBuffer.append(1);
            stringBuilder.append(1);
        }
    }).start();

    new Thread(() -> {
        try {
            Thread.sleep(2000);

            System.out.println("StringBuffer.length: "+ stringBuffer.length()); // thread safe 함
            System.out.println("StringBuilder.length: "+ stringBuilder.length()); // thread unsafe 함
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
  }
}
출처: https://inpa.tistory.com/entry/JAVA-☕-String-StringBuffer-StringBuilder-차이점-성능-비교 [Inpa Dev 👨‍💻:티스토리]

 

StringBuffer.length: 20000
StringBuilder.length: 19628

출처: https://inpa.tistory.com/entry/JAVA-☕-String-StringBuffer-StringBuilder-차이점-성능-비교 [Inpa Dev 👨‍💻:티스토리]

 두 개의 스레드가 있고 각 스레드는 배열 요소를 1만번 추가하게 되는 로직입니다. 그러면 결과적으로 문자열 배열의 크기는 2만이 나와야 합니다.

 

 하지만, StringBuider의 결과 값은 2만번에 미치지 못하는 결과로, Thread Safe하지 못한 것을 볼 수 있습니다.

 

 동기화를 제외한 단순 성능은 스레드와 관련된 연산이 없기 때문에  StringBuilder가 조금 더 빠릅니다. 하지만 멀티 스레드 환경에서는 StringBuffer로 사용하는 것이 안정적일 것입니다.

 

 

 

각각의 상황에 따라 정리를 하자면 다음과 같습니다.

 

String은 짧은 문자열을 더할 경우에 사용하고, 그 외에는 StringBuffer와 StringBuilder가 효율적입니다. 


 그리고, StringBuilder는 스레드에 안전한지 여부가 전혀 관계 없는 서비스를 개발할 때가 적절합니다

 

 StringBuffer는 스레드에 안전한 프로그램이 필요할 때나, 개발 중인 시스템의 부분이 스레드에 안전한지 모를 경우에 효율적입니다.

 

 

 

 

참고 자료

String-StringBuffer-StringBuilder-차이점-성능-비교 [Inpa Dev 👨‍💻:티스토리]
https://inpa.tistory.com/entry/JAVA-%E2%98%95-String-StringBuffer-StringBuilder-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90

Java-StringBuffer와-StringBuilder의-차이
https://velog.io/@p_zane/Java-StringBuffer%EC%99%80-StringBuilder%EC%9D%98-%EC%B0%A8%EC%9D%B4

[자바] String, StringBuilder, StringBuffer의 차이 [길은 가면, 뒤에 있다.:티스토리]
https://12bme.tistory.com/42