String
String과 다른 클래스(StringBuffer, StringBuilder)의 차이점은 String은 불변(immutable) 하다는 점이다.
String 객체는 한번 생성되면 할당된 메모리 공간이 변하지 않는다.
‘+’ 연산자 또는 concat 메서드를 통해 기존에 생성된 String 클래스 객체 문자열에 다른 문자열을 붙여도 기존 문자열에 새로운 문자열을 붙이는 것이 아니라,
새로운 String 객체를 만든 후, 새 객체에 연결된 문자열을 저장하고 그 객체를 참조하도록 한다.
즉, 한번 생성된 객체의 내부 내용을 변화시킬 수 없다.
String str = "hello"; // String str = new String("hello");
str = str + " world"; // [ hello world ]
기존에 “hello” 값이 들어가있던 String 클래스의 참조 변수 str이 “hello world” 라는 값을 가지고 있는 새로운 메모리 영역을 가리키게 변경된다.
그리고 처음 선언했던 “hello”로 값이 할당되어 있던 메모리 영역은 Garbage로 남아있다가 GC(garbage collection)에 의해 사라진다.
String 클래스는 불변하기 때문에 문자열을 수정하는 시점에 새로운 String 인스턴스가 생성된 것이다.
따라서 String 객체는 문자열 연산이 많은 경우 사용하면 성능이 좋지 않다.
힙 메모리에 많은 임시 가비지가 생성되어 힙메모리 부족으로 어플리케이션 성능에 영향을 끼칠 수 있기 때문이다.
이를 위해 자바에서 가변(mutable)성을 가지는 StringBuffer/StringBuilder 클래스를 도입했다.
StringBuffer/StringBuilder
String과 다르게 문자열 연산 등으로 기존 객체의 공간이 부족해진 경우, 기존의 버퍼 크기를 늘리며 유연하게 동작한다.
StringBuffer와 StringBuilder 클래스가 제공하는 메서드는 서로 동일하다.
두 클래스의 차이점은 동기화 여부이다.
- StringBuffer: 각 메서드별로 Synchronized Keyword가 존재하여, 멀티스레드 환경에서도 동기화를 지원한다.(thread-safe)
- StringBuilder: 동기화를 보장하지 않기 때문에 멀티스레드 환경에서는 적합하지 않지만 동기화를 고려하지 않아 단일쓰레드에서의 성능은 StringBuffer보다 뛰어나다.
(참고로 String은 불변성을 가지기 때문에 멀티스레드 환경에서 안정성을 가지고 있다.)
따라서 멀티스레드 환경이라면 값 동기화 보장을 위해 StringBuffer를 사용하고,
단일스레드 환경이라면 StringBuilder를 사용하는 것이 좋다.
정리
성능: StringBuilder > StringBuffer >>>> String
String : 문자열 연산이 적고 멀티쓰레드 환경일 경우
StringBuffer : 문자열 연산이 많고 멀티쓰레드 환경일 경우
StringBuilder : 문자열 연산이 많고 단일쓰레드이거나 동기화를 고려하지 않아도 되는 경우
그동안 알고리즘 문제들을 풀 때, String에서 +연산을 반복적으로 수행하면 가끔가다가 시간 초과가 날 때가 있었다.
그럴 때 StringBuilder로 바꿔 풀면 통과가 되었는데, 이번 포스팅을 정리하면서 그 이유에 대해 자세히 알게 되었다.
앞으로 상황에 맞게 적절한 클래스를 사용하도록 해야겠다.
참고
'BACK > JAVA' 카테고리의 다른 글
[JAVA] 기본형과 참조형 (0) | 2024.01.30 |
---|---|
[JAVA] 클래스와 데이터 (0) | 2024.01.30 |
[JAVA] Collection 최솟값, 최댓값 구하기 (0) | 2023.04.05 |
[JAVA] ArrayList.indexOf() 사용법 (0) | 2023.03.31 |
[JAVA] 문자열 배열을 길이 순으로 정렬하기 (0) | 2023.03.04 |