1. String
1-1. 특징
- String 객체는 immutable 이다. 즉, 한번 생성되면 String 객체가 변할 수 없다.
- 문자열, 숫자, char 등을 concat 할때는 StringBuffer, StringBuilder 를 사용할 수 있지만 단순한 경우에는 + 를 활용해 직접 합쳐도 된다.
- 수정할 경우, 수정마다 매번 새로운 객체를 생성함.
2. StringBuffer 와 StringBuilder 차이점
2-1. 특징
- 기본적으로 두 클래스가 제공하는 메소드는 동일하지만 StringBuffer는 멀티 쓰레드 상태에서 동기화를 지원한다. (각 메소드 별로 synchronized 키워드가 존재)
- String 을 + 를 활용해 합치는 경우 매번 인스턴스를 생성하기 때문에 성능상에 이슈가 많다. 이런 성능 이슈를 개선하기위해 JDK 1.5 버전 이후에는 컴파일 단계에서 StringBuilder로 컴파일 되도록 변경되기 때문에 + 를 활용해도 성능상에 큰 이슈는 없다.
3. 추가내용
3-2.
String 클래스는 변경이 불가능한 immutable 클래스이다.
- StringBuffer 클래스가 String 클래스 보다 항상 더 나은 성능을 가지고 있다면 왜 자바를 설계한 사람들은 String 클래스를 기본 문자열처리 클래스로 정했을까?
- substring(), toLowerCase(), concat(), trim() 등의 메소드를 생각하면 String 클래스는 변경이 가능한 클래스처럼 보이지만 실제로는 이러한 메소드들은 원래 객체와 다른 새로운 String 객체를 만들어 반환한다. 또 하나의 String 객체가 생성되기 때문에 원래 String 객체는 가지고 있는 문자열이 변경되지 않으며 여전히 사용가능한 채로 남는다.
- 아래와 같은 코드에서 String 의 new 연산은 n번 실행된다.
String result = "";
for (int i=0; i < n; i++) {
result += target;
}
- 위와 같은 이유로 Strgin 클래스의 변경은 객체를 생성하기 위하여 시스템(시간, 메모리 등)을 낭비한다고 생각되는 경향이 있다.
3-3. 왜 immutable(변경불가) 클래스인가?
3-3-1. immutable 클래스의 특징
1) 클래스가 가지고 있는 값(String 클래스에서 문자열)은 오직 생성자에서만 생성될 수 있으며, 그 값을 변경할 수 있는 어떠한 메소드도 가지고 있지 않아야 한다. 만약 변경을 원한다면, 원하는 값을 가진 새로운 객체를 생성한다.
2) 변경은 적고 읽기(문자열의 참조)만 많은 경우, 또는 여러 쓰레드나 객체에서 공유하는 경우 synchronization(동기화) 와 같은 특별한 안정장치 없이도 안전하게 공유될 수 있다.
3) 대부분의 문자열이 복잡한 문자열 처리과정보다는 한번 설정된 문자열들을 여러 곳에서 공유하는 경우가 많으므로 자바에서 기본 문자열을 처리하는 클래스로 String 클래스를 immutable 패턴으로 설정하였다.
3-4. StringBuffer 클래스는 변경이 가능한 Mutable 클래스이다.
3-4-1. 특징
- append(), insrt(), delete() 등의 메소드를 통하여 StringBuffer 객체가 가지고 있는 문자열을 변경 할 수 있으며, 이때, String 클래스 처럼 새로운 객체를 생성하지 않고 기존의 문자열을 변경한다.
- 아래 코드에서 StringBuffer 는 new 연산자가 한번만 실행된다.
StringBuffer result = new StringBuffer();
for(int i=0; i < n; i++) {
result.append(target);
}
- 위와 같은 경우 객체 생성을 하지 않으므로, String 클래스 보다 효율적이라고 생각하기쉽지만 동기화(synchronization)을 보장해야 하기 때문에 단순한 참조에서는 상대적으로 String 보다 나쁜 성능을 보인다.
- 따라서 단순 참조가 많은 경우 StringBuffer 클래스보다 String 클래스가 유리하다. 물론, StringBuffer 클래스는 종기화 되어 있으므로 멀티쓰레드에 대하여 안전하다.
- 또한, StringBuffer 객체는 문자열을 다루는 다른 메소드들에서 사용되기 위하여, toString() 메소드를 통하여 String 객체를 생성하게 된다. 이때, 일반적으로 String 객체의 생성과 함께, 가지고 있는 문자열에 대한 복사가 이루어진다. 물론, 자바 규약은 성능 향상을 위하여 String 객체의 생성 후에 문자열을 복사하지 않고 StringBuffer 객체와 문자열을 공유하여 참조하는 프록시 패턴을 적용하는 것을 허용하고 있다. 그러나 이것은 반드시 그런 것은 아니며, 프록시 패턴의 특성상 StringBuffer 객체에 변경이 가해지면 프록시는 바로 해제되며 그 시점에서 문자열의 복사가 이루어 진다. (프록시 패턴의 적용은 필수 요건이 아니며, 자바 가상 머신 구현체에 따라 다를 수 있으며, 사용상의 차이는 전혀 없고 성능상의 차이만을 보일 뿐이다.)
3-5. 성능 향상에 대한 결론
- StringBuffer 클래스는 문자열을 추가하기 위하여 append() 와 같은 메소드를 사용할 때 String 클래스보다 뛰어난 성능을 보인다. 그러나 StringBuffer 객체의 생성 및 toString() 메소드를 통한 String 객체의 생성을 반드시 필요로 하므로 더 많은 시간 및 메모리 자원의 낭비를 초래한다.
-
String 클래스는 StringBuffer 클래스와 비교하여 인스턴스화를 통하여 객체를 생성할 때 상대적으로 적은 자원을 소모하며, toString() 메소드를 통하여 String 객체로 바꿀 필요가 없다.
-
StringBuffer 클래스는 하나의 문자열에 대하여 다른 문자나 문자열의 추가가 여러 번 이루어 지는 경우 유리하며, 단 한번의 문자열 추가에 대하여 StringBuffer 클래스를 사용하는 것은 오히려 시간 및 메모리 자원 낭비를 초래하게 된다.
- 단순히 StringBuffer 클래스가 soString() 을 통해 새로운 String 객체 생성이 필요 없다고 가정하면, String 의 + 연산자는 횟수가 많아지면 사용이 불가능 할 정도로 성능이 좋지 않다. 때문에 문자열을 가지고 할 일이 많다면 반드시 StringBuffer() 나 멀티쓰레드로 동기화를 고려하지 않는다면 StringBuilder()를 사용하도록 하자.
4. 참고
- http://leegaworld.tistory.com/8
- http://javacan.tistory.com/entry/39
- http://deblan2.egloos.com/viewer/419830
댓글
댓글 쓰기