본문 바로가기
Java/Java

자바 String StringBuffer StringBuilder 비교, 차이점 알아보기!

by 산코디 2023. 1. 29.





안녕하세요.

오늘은 자바에서 문자열 연산에 사용되는 String class에 대해 정리해 보려고 합니다.
String 연산에 사용되는 class는 크게
String, StringBuffer, StringBuilder
이렇게 세 종류가 있습니다. 결괏값만 두고 봤을 땐 차이가 없지만 내부적으로 처리하는 과정이 달라 서비스의 성능까지 영향이 있기 때문에 차이점을 알고 사용하신다면 자바 개발 업무에 많은 도움이 되실 거예요!
그렇다면 각 class별로 어떤 차이점과 특징이 있는지 간단한 예제를 통해서 하나씩 알아보겠습니다.


불변성과 가변성
불변성 : immutable, 값이 할당된 공간이 변하지 않는 특성을 의미
가변성 : mutable, 값이 할당된 공간이 변하는 특성을 의미

들어가기 전에 먼저 알아야 할 것은 불변성과 가변성입니다.
변수에 값을 할당하고 변경, 삭제할 때 그 값의 공간이 변하는지 변하지 않는지에 대한 내용이며, 오늘 정리하는 문자열 class는 모두 이와 연관이 있습니다. 그럼 어떻게 달라지는지 볼까요?!


1. class별 특징 알아보기

 

String 특징
불변성
문자열 연산이 적고 멀티스레드 환경인 경우 적절
변하지 않는 문자열을 자주 사용할 경우 적절

 

StringBuffer 특징
가변성
동기화 지원
문자열 연산이 많고 멀티쓰레드 환경인 경우 적절
멀티쓰레드 환경과 동기화를 지원하기 때문에 StringBuilder보다 성능이 떨어짐

 

StringBuilder 특징
가변성
동기화 미지원
문자열 연산이 많고 싱글스레드 환경인 경우 적절
싱글쓰레드 환경과 동기화를 지원하지 않기 때문에 StringBuffer보다 성능이 좋음


위의 세 종류의 class는 모두 문자열을 다루는 class이지만 위의 각 특징들처럼 차이점을 가지고 있습니다. 가변성과 불변성에 따라 어떻게 달라지는 건지 예제를 통해 알아보겠습니다.

반응형

2. 각 class별 저장 위치

		
String str = "a";

StringBuffer buffer = new StringBuffer();
buffer.append("a");

StringBuilder builder = new StringBuilder();
builder.append("a");

System.out.println("값 변경 전");
System.out.println("---------------------------------------------");
System.out.println(" * String");
System.out.println("   - value : " + str);
System.out.println("   - hashcode : " + str.hashCode());
System.out.println("---------------------------------------------");
System.out.println(" * StringBuffer");
System.out.println("   - value : " + buffer);
System.out.println("   - hashcode : " + buffer.hashCode());
System.out.println("---------------------------------------------");
System.out.println(" * StringBuilder");
System.out.println("   - value : " + builder);
System.out.println("   - hashcode : " + builder.hashCode());
System.out.println("---------------------------------------------");

str += "b";
buffer.append("b");
builder.append("b");

System.out.println("값 변경 후");
System.out.println("---------------------------------------------");
System.out.println(" * String");
System.out.println("   - value : " + str);
System.out.println("   - hashcode : " + str.hashCode());
System.out.println("---------------------------------------------");
System.out.println(" * StringBuffer");
System.out.println("   - value : " + buffer);
System.out.println("   - hashcode : " + buffer.hashCode());
System.out.println("---------------------------------------------");
System.out.println(" * StringBuilder");
System.out.println("   - value : " + builder);
System.out.println("   - hashcode : " + builder.hashCode());
System.out.println("---------------------------------------------");

위와 같이 각 class별로 문자열 "a" 값을 동일하게 줬고 해당 할당된 변수마다 hashcode 값을 조회하였습니다. 그 후 값을 변경한 후의 hashcode값을 조회하였습니다.


실행 결과

실행 결과를 보게 되면 초기값을 할당하고 hashcode값을 조회했을 때에는 크게 다른 점은 없어 보입니다. 하지만 각 변수마다 "b"값을 추가한 후의 hashcode값은 조금 다른 부분이 있습니다.
String의 경우는 hashcode값이 바뀌었고, StringBuffer와 StringBuilder는 hashcode값이 바뀌지 않았습니다.
이 부분이 처음에 설명했던 불변성과 가변성입니다.
hashcode값이 바뀌었다는 것은 값의 할당 위치가 변경됐다는 뜻으로 불변성을 의미하며,
hashcode값이 바뀌지 않았다는 것은 값의 할당 위치가 변경되지 않고 값이 변경된 뜻으로 가변성을 의미합니다.


최종 정리
  할당 위치 쓰레드 방식 상대적인 처리 속도
String 불변성 - -
StringBuffer 가변성 멀티 쓰레드 느림
StringBuilder 가변성 싱글 쓰레드 빠름

마무리

오늘은 이렇게 자바의 문자열을 다루는 class들의 특징과 차이점을 알아봤습니다. 어떤 방식이 좋다기보다는 어떤 상황에 어떤 class를 활용하여 최대한의 퍼포먼스를 내는지가 중요합니다. String 하나만 알고 있을 때보다 StringBuffer를 알았을 때, 거기에 StringBuilder까지 알고 있다면 어떤 모듈을 만들 때 선택의 폭이 넓어지며 역량을 높이는데 많은 도움이 되실 거예요!
저 또한 아무것도 모르던 시절 주구장창 String으로만 문자열 할당을 하면서 개발 업무를 해왔던 기억이 있습니다.. :)


그럼 오늘도 저의 작고 소중한 글을 읽어주셔서 감사합니다!





 

반응형