[Java] String vs StringBuffer vs StringBuilder
1. String
immutable 불변클래스
초기 문자열을 할당 한 후 부터 수정이 불가하다.
변경된것처럼 보이는 이유는, 내부적으로 변경된 문자열을 새롭게 만들기 때문이다. 즉 기존에 만들어 놓은 문자열을 수정하는 것이 아니라, 기존에 있는 문자열은 그대로 둔 상태에서, 변경된 문자열을 새롭게 만든다. 이 때문에 String을 기반 문자열을 substring이나 concat, toLowercase등의 메서드를 실행했을 때 매번 새롭운 String 객체가 만들어 지는 것이다. 이 대문에 시스템 자원(시간,메모리)등이 낭비될 여지가 있다.
그렇다면 왜? immutable기능을 String은 탑재하고 있을까? 바로 안정성 때문이다. 읽기 목적이 뚜렷한 경우 String 생성시 처음에만 문자열을 할당하고 그 이후엔 수정하지 말고, 읽기만 하라는 컨셉이다.
또한, immutable 클래스의 가장 큰 장점은 안전하게 공유될 수 있다는 점이다. 여러 쓰레드나 객체에서 참조하는 경우 synchronization(동기화) 없이도 데이터가 안전하게 공유되기 때문이다. 따라서 변경하지 않고 읽기용 또는 공유 목적 하에 있는 문자열은 String immutable 클래스를 사용하는 것이 바람직하다.
2. StringBuffer
mutable 가변클래스 && synchronization(동기화) 보장, 멀티 스레드 보장
String 클래스와 다르게 문자열을 수정할 수 있습니다. 즉, 처음 할당한 기존 문자열에 대해 변경을 시도할 경우 새로운 객체를 생성하지 않고 기존문자열을 수정하여 문자열을 변경할 수 있습니다. 하지만 synchronization(동기화)를 보장하기 때문에, 만약 변경이 많지 않은 문자열에 대해 문자열 수정을 할 경우 String 클래스보다 더 좋은 성능을 발휘할 것 같지만, synchronization(동기화) 내부적 처리로 인해 오히려 나쁜 성능을 보일 수 있습니다. 따라서 단순 참조가 많은 경우에는 String 클래스를 사용하고, 참조가 많거나 문자열 변경을 많이 해야 한다면, StringBuffer클래스를 사용하는 것이 좋습니다. 또한 synchronization(동기화) 보장하기 때문에 멀티 스레드 환경에서 안정성이 보장됩니다.
추가적으로 알아둬야 할 부분은 StringBuffer 객체는 문자열을 다루는 다른 메소드에서 사용되기 위해 , toString()메서드를 사용 할 경우 String객체를 생성해 반환합니다. 이때 String 객체 생성과 함께 기존 문자열 복사가 이루어집니다. (toString()은 결국 String 객체를 생성함)
** 자바 규약 성능 파트에서 String객체 생성 후에 문자열을 복사하지 않고, StringBuffer 객체와 문자열을 공유, 참조하는 프록시 패턴을 적용하는 것을 허용하고 있으나, StringBuffer 객체에 변경이 발생되면 프록시 패턴은 해체되고, 또한 그 시점에 문자열이 복사되기 때문에 (프록시 패턴은 필수요건이 아니며, JVM에 따라 다를 수 있으며, 사용상 차이는 없고, 성능 상 차이가 있습니다.)
3. StringBuilder
mutable 가변클래스 && 단일 스레드에서만 보장
StringBuilder는 JDK 1.5 에서 새롭게 추가된 클래스이며, StringBuffer와 기능은 모두 같으나, synchronization(동기화) 보장하지 않기 때문에 단일 스레드에서만 안전합니다. 즉 멀티 스레드 환경에서는 동기화가 보장되지 않고 문제가 발생될 수 있음을 뜻합니다.
4. String vs StringBuffer vs StringBuilder
어떤 기준으로 선택해야 하는가??
JDK 1.4 이하에서는 String 타입은 그대로 컴파일 되지만, JDK 1.5 이후부터 성능이슈로 인해 컴파일러가 자동으로 String 타입을 StringBuilder로 치환하여 컴파일 합니다. 그렇다고 완벽하게 성능 이슈가 해결되는 것은 아닙니다. 만약 반복루프를 통한 문자열 변화를 계속한다면, StringBuilder 치환도 소용없는 것이지요.
정리하자면, 읽기용이나 공유용도로 문자열을 사용해야 한다면, String 타입을 ...
(단일 문자열 참조일 경우)
문자열 수정을 해야 하면서 멀티 스레드 환경이라면, StringBuffer를 ...
(동기화 기능 O -> 멀티 스레드 환경에서 안정성 보장)
문자열 수정을 해야 하면서 싱글 스레드 환경이라면, StringBuffer를 ...
(동기화 기능 X -> 싱글 스레드 환경에서 사용 권장)
+PS
문자열을 추가하기 위한 append() 메서드에 대해서 StringBuffer는 String 보다 월등한 성능을 보인다. 하지만 toString()메서드에 대해서는 오히려 String객체 생성을 하는 내부적인 처리 때문에, StringBuffer가 String 보다 더 많은 자원을 소모한다.
그에 비하여, String 클래스는 StringBuffer 와 비교하여 인스턴스화를 통하여 객체를 생성할 때 상대적으로 적은 자원을 소모하며, toString() 메서드를 통하여 String 객체로 바꿀 필요가 없다. 이 때문에 StringBuffer 는 하나의 문자열에 대하여 다른 문자나 문자열 추가가 여러 번 행해지는 곳에서 유리하며, 단 한번의 문자열 추가에 대해서는 StringBuffer를 사용하는 것은 오히려 독이다.