본문 바로가기

# 02/Java

[Java] String과 StringBuffer, StringBuilder의 차이점

반응형

자바에서 String과 StringBuffer, StringBuilder의 차이점을 알아본다.

이들의 공통점은 모두다 String(문자열)을 저장하고 관리하는 클래스들이다.

어떤 차이점이 있을까?

String과 (StringBuffer, StringBuilder)의 차이점은 String은 immutable(불변)하고 StringBuffer, StringBuilder는 mutable(가변)하다는 점이다.

쉽게 말해서 String은 new 연산을 통해 생성되면 그 인스턴스의 메모리 공간은 절대 변하지 않는다.

그래서 + 연산이나 concat을 이용해서 문자열에 변화를 줘도 메모리 공간이 변하는 것이 아니라 새로운 String객체를 new로 만들어서 새로운 메모리 공간을 만드는 것이다.

이렇게 새로운 문자열이 만들어지면 기존의 문자열은 가비지 콜렉터에 의해 제거되야 하는 단점(언제 제거될지 모름)이 있다.

또한 이러한 문자열 연산이 많아질 때 계속해서 객체를 만드는 오버헤드가 발생하므로 성능이 떨어질 수 밖에 없는 단점이 있다. (+연산에 내부적으로 char배열을 사용함)

대신 String 클래스의 객체는 불변하기 때문에 단순하게 읽어가는 조회연산에서는 타 클래스보다 빠르게 읽을 수 있는 장점이 있다. (+불변하기 때문에 멀티쓰레드환경에서 동기화를 신경쓸 필요가 없음(장점))

결론 => String 클래스는 문자열 연산이 적고 조회가 많을 때 멀티쓰레드 환경에서 사용하면 좋음.

StringBuffer와 StringBuilder 클래스는 String과 다르게 mutable(변경가능)하다.

즉 문자열 연산에 있어서 클래스를 한번만 만들고(new), 연산이 필요할 때 크기를 변경시켜서 문자열을 변경한다.

그러므로 문자열 연산이 자주 있을 때 사용하면 성능이 좋다!

심지어 StringBuffer와 StringBuilder 클래스의 메서드들이 같으므로 호환(?)이 가능하다.

그렇다면 StringBuffer와 StringBuilder의 차이는 무엇일까?

차이점은 StringBuffer는 멀티쓰레드환경에서 synchronized키워드가 가능하므로 동기화가 가능하다. 즉, thread-safe하다.

StringBuilder는 동기화를 지원하지 않기 때문에 멀티쓰레드환경에서는 적합하지 않다.

대신 StringBuilder가 동기화를 고려하지 않기 때문에 싱글쓰레드 환경에서 StringBuffer에 비해 연산처리가 빠르다.

결론 => 문자열 연산이 많을 때 멀티쓰레드환경에서는 StringBuffer, 싱글쓰레드또는 쓰레드를 신경쓰지 않아도 되는 환경에서는 StringBuilder를 사용하는 것이 적절하다.

다시 한번 정리하면,

String클래스는 불변 객체이기 때문에 문자열 연산이 많은 프로그래밍이 필요할 때 계속해서 인스턴스를 생성하므로 성능이 떨어지지만 조회가 많은 환경, 멀티쓰레드 환경에서 성능적으로 유리합니다.

StringBuffer클래스와 StringBuilder클래스는 문자열 연산이 자주 발생할 때 문자열이 변경가능한 객체기 때문에 성능적으로 유리합니다.

StringBuffer와 StringBuilder의 차이점은 동기화지원의 유무이고 동기화를 고려하지 않는 환경에서 StringBuilder가 성능이 더 좋고, 동기화가 필요한 멀티쓰레드 환경에서는 StringBuffer를 사용하는 것이 유리합니다.

* StringBuffer와 StringBuilder는 성능으로 따졌을 때 2배의 속도차이가 있다고 하지만 참고사이트의 속도 차이 실험 결과 append()연산이 약 1억6천만번 일어날 때 약 2.6초의 속도차이를 보인다고 합니다.

(String은 +연산이 16만번이상 넘어가게 되면 10초이상 걸리면서 못 쓸정도의 성능을 보입니다.)

따라서 문자열연산이 많지만 엄청나게 일어나지 않는 환경이라면 StringBuffer를 사용해서 thread-safe한 것이 좋다는 생각입니다.

* JDK1.5이상부터 String에서 +연산으로 작성하더라도 StringBuilder로 컴파일하게 만들어 놨다지만 여전히 String클래스의 객체 생성하는 부분을 동일하므로 StringBuffer,StringBuilder 사용이 필요함.

+ StringBuffer, StringBuilder의 경우 buffer size를 초기에 설정해야하는데 이런 생성, 확장 오버로드가 걸려 버퍼사이즈를 잘못 초기화할 경우 성능이 좋지 않을 수 있음.

+ String클래스가 컴파일러분석단계에서 최적화될 가능성이 있기때문에 간혹 성능이 잘나오는 경우도 있음. 문자열 연산이 많지 않은 경우는 그냥 사용해도 무방.

런타임에서 문자열조합이 많아질 경우 String은 여전히 성능이 아주 안좋기 때문에!

+, concat을 사용하는 사고(?)를 치면 안된다. 특히 현업에서....



출처: https://jeong-pro.tistory.com/85 [기본기를 쌓는 정아마추어 코딩블로그]



* String, StringBuffer, StringBuilder 차이점과 장단점.


Java를 사용하면 종종 접하게 되는 문자열 클래스들입니다. (기술면접시 만나게 되는 문제 중 하나.)


String, StringBuffer, StringBuilder.. 모두 문자열을 저장하고, 관리하는 클래스입니다.

굳이 여러가지를 만들어놓은 이유는 무엇일까요.


1) String

먼저 String과 다른 클래스(StringBuffer, StringBuilder)의 차이점은 두 문자열 클래스의 아주 기본적인 차이는 String은 immutable(불변), StringBuffer는 mutable(변함)에 있습니다.


String은 문자열을 대표하는 것으로 문자열을 조작하는 경우 유용하게 사용할 수 있습니다. 문자열, 숫자, char 등은 concat할때는 StringBuffer, StringBuilder를 사용할 수 있습니다. 단, 복잡한 경우 의미가 있고, 단순한 경우에는 굳이 StringBuffer, StringBuilder를 쓰지 않고 +연산자를 활용해 직접 합지면 됩니다.


String 객체는 한번 생성되면 할당된 메모리 공간이 변하지 않습니다. + 연산자 또는 concat 메서드를 통해 기존에 생성된 String 클래스 객체 문자열에 다른 문자열을 붙여도 기존 문자열에 새로운 문자열을 붙이는 것이 아니라,


새로운 String 객체를 만든 후, 새 String 객체에 연결된 문자열을 저장하고, 그 객체를 참조하도록 합니다. (즉, String 클래스 객체는 Heap 메모리 영역(가비지 컬렉션이 동작하는 영역)에 생성. 한번 생성된 객체의 내부 내용을 변화시킬 수 없습니다. 기존 객체가 제거되면 Java의 가비지 컬렉션이 회수합니다.)


String 객체는 이러한 이유로 문자열 연산이 많은 경우, 그 성능이 좋지 않습니다.


하지만, Immutable한 객체는 간단하게 사용가능하고, 동기화에 대해 신경쓰지 않아도 되기때문에(Thread-safe),  내부 데이터를 자유롭게 공유 가능합니다.


2) StringBuffer와 StringBuilder

그럼 StringBuffer와 StringBuilder 클래스를 한번 볼까요?


StringBuffer/StringBuilder는 String과 다르게 동작합니다.

문자열 연산 등으로 기존 객체의 공간이 부족하게 되는 경우,


기존의 버퍼 크기를 늘리며 유연하게 동작합니다. StringBuffer와 StringBuilder 클래스가 제공하는 메서드는 서로 동일합니다.


그럼 두 클래스의 차이점은 무엇일까요? 바로 동기화 여부입니다.

- StringBuffer는 각 메서드별로 Synchronized Keyword가 존재하여, 멀티스레드 환경에서도 동기화를 지원.
- 반면, StringBuilder는 동기화를 보장하지 않음.


그렇기때문에 멀티스레드 환경이라면 값 동기화 보장을 위해 StringBuffer를 사용하고,


단일스레드 환경이라면 StringBuilder를 사용하는 것이 좋습니다. 단일 스레드환경에서 StringBuffer를 사용한다고 문제가 되는 것은 아니지만, 동기화 관련 처리로 인해 StringBuilder에 비해 성능이 좋지 않습니다.


String은 짧은 문자열을 더할 경우 사용합니다.

StringBuffer는 스레드에 안전한 프로그램이 필요할 때나, 개발 중인 시스템의 부분이 스레드에 안전한지 모를 경우 사용하면 좋습니다.

StringBuilder는 스레드에 안전한지 여부가 전혀 관계 없는 프로그램을 개발할 때 사용하면 좋습니다.


사실 JDK 1.5버전 이전에서는 문자열연산(+, concat)을 할때에는 조합된 문자열을 새로운 메모리에 할당하여 참조함으로 인해서 성능상의 이슈가 있었습니다. 그러나 JDK1.5 버전 이후에는 컴파일 단계에서 String 객체를 사용하더라도 StringBuilder로 컴파일 되도록 변경되었습니다. 그리하여 JDK 1.5 이후 버전에서는 String 클래스를 활용해도 StringBuilder와 성능상으로 차이가 없어졌습니다. 하지만 반복 루프를 사용해서 문자열을 더할 때에는 객체를 계속 추가한다는 사실에는 변함이 없습니다. 그러므로 String 클래스를 쓰는 대신, 스레드와 관련이 있으면 StringBuffer를, 스레드 안전 여부와 상관이 없으면 StringBuilder를 사용하는 것을 권장합니다.


단순히 성능만 놓고 본다면 연산이 많은 경우, StringBuilder > StringBuffer >>> String 입니다.



출처: https://12bme.tistory.com/42 [길은 가면, 뒤에 있다.]

반응형