문자열을 저장하는 String은 내부의 문자열을 수정할 수 없다. 예를 들어 String의 replace() 메소드는 내부의 문자를 대치하는 것이 아니라, 대치된 새로운 문자열을 리턴한다. String 객체를 + 연산할 경우에도 마찬가지다.
String data = "ABC";
data += "DEF";
"ABC"에 "DEF"가 추가되었기 때문에 한 개의 String 객체가 사용되었다고 생각할 수 있지만, String 객체는 내부 데이터를 수정할 수 없으므로, "ABC"에 "DEF"가 추가된 "ABCDEF"라는 새로운 String 객체가 생성된다. 그리고 data 변수는 새로운 String객체를 참조하게 된다.
문자열을 결합하는 + 연산자를 많이 사용하면 할수록 그만큼 String객체의 수가 늘어나기 때문에 프로그램의 성능을 느리게 하는 요인이 된다. 문자열을 변경하는 작업이 많을 경우에는 String 클래스를 사용하는 것 보다는 java.lang package의 StringBuffer 또는 StringBuilder 클래스를 사용하는 것이 좋다. 이 두 클래스는 내부 버퍼(buffer : 데이터를 임시로 저장하는 메모리)에 문자열을 저장해 두고, 그 안에서 추가, 수정, 삭제 작업을 할 수 있도록 설계되어 있다. String 처럼 새로운 객체를 만들지 않고도 문자열을 조작할 수 있는 것이다.
String 은 immutable(불변)하고, StringBuilder, StringBuffer는 mutable(가변)하다. String은 new 를 통해 생성되면 그 인스턴스의 메모리 공간은 절대 변하지 않는다. 그래서 + 연산이나 concat을 이용해서 문자열을 변형시켜도 메모리 공간이 변하는 것이 아니라 위의 그림처럼 새로운 String 객체를 만들어서 새로운 메모리 공간을 얻는 것이다.
StringBuffer | StringBuilder |
멀티 스레드 환경에서도 가능(thread-safe) | 싱글 스레드 환경에서만 |
StringBuilder 의 기본 생성자는 16개의 문자들을 저장할 수 있는 초기 버퍼를 만들고, StringBuilder(int capacity) 생성자는 capacity로 주어진 개수만큼 문자들을 저장할 수 있는 초기 버퍼를 만든다. StringBuilder는 버퍼가 부족할 경우 자동으로 버퍼 크기를 늘리기 때문에 초기 버퍼의 크기는 그다지 중요하지 않다. StringBuilder(String str) 생성자는 str로 주어진 매개값을 버퍼의 초기값으로 저장한다.
append("") | 문자열 끝에 주어진 매개값을 추가 |
insert(int offset,"") | 문자열 중간에 주어진 매개값을 추가 |
delete(int start, in end) | 문자열의 일부분을 삭제 |
deleteCharAt(int index) | 문자열에서 주어진 index의 문자를 삭제 |
replace(int start, int end, String str) | 문자열의 일부분을 다른 문자열로 대치 |
StringBuilder reverse() | 문자열의 순서를 뒤바꿈 |
setCharAt(int index, char ch) | 문자열에서 주어진 index의 문자를 다른 문자로 대치 |
[표 StringBuilder의 메소드들]
public Class test{
public static void main(String[] args){
StringBuilder sb = new StringBuilder(); //객체 생성
//문자열 끝에 추가
sb.append("java");
sb.append(" program study");
System.out.println(sb.toString());
sb.insert(4, "2");//4번째 문자 뒤에 2를 삽입
System.out.println(sb.toString());
sb.setCharAt(4, "6");//4번째 문자 뒤의 문자를 6으로 변경
System.out.println(sb.toString());
sb.replace(6, 13, "Nope");//6번째 문자 뒤부터 13번째 문자까지를 "Nope"으로 대치
sb.delete(4, 5) //5번째 문자를 삭제
String result = sb.toString(); //버퍼에 있는 것을 String타입으로 전환
System.out.println(result);
}
}
String | StringBuffer | StringBuilder | |
공통점 | String(문자열)을 저장하고 관리하는 클래스 | ||
메모리 공간 | immutable(불변) 객체 | muttable(가변) 객체 | |
동기화 지원 여부 | 불변하기 때문에 동기화를 신경 쓸 필요가 없다. -> 조회가 많은 환경, 멀티 스레드 환경에서 유리 | synchronized 키워드가 가능 ->동기화 가능(thread-safe) | 동기화 지원 X -> 싱글 스레드 또는 스레드를 신경쓰지 않아도 되는 환경에서 적합 |
정리
String, StringBuffer, StringBuilder는 모두 문자열을 저장하고 관리하는 클래스이다. String은 불변 객체이기 때문에 연산자나 concat을 써서 변화를 주면, 사용자 화면상에 System.out.println()으로 찍어보면 변화가 일어난 객체가 리턴된 것 처럼 보이지만 내부적으로는 새로운 String 객체를 생성해서 참조하게 되는 것이다. 문자열 연산이 많이 일어나면 일어날 수록 새로운 객체가 생성되는 오버헤드가 발생하므로 성능이 떨어지게 되는 단점이 있다. 반면에 StringBuffer, StringBuilder는 가변 객체이기 때문에 문자열을 변형시켜도 새로운 객체를 생성하지 않고 실제로 객체 내부를 변형시킨다. 이 둘의 차이점은 멀티 스레드 환경에서 동기화를 지원해주느냐의 여부(StringBuffer는 지원) 와 그에 따른 성능의 차이이다.(StringBuilder는 동기화를 신경쓰지 않아도 되는 환경이라서 더 빠르다. 약 2배 차이라는데 실제로는 append()연산이 1억 6천만번 일어날 때 약 2.6초 정도의 차이라고 한다.)
출처
- 이것이 자바다
- 정아마추어님의 코딩 블로그
'Java' 카테고리의 다른 글
제네릭 (0) | 2019.06.03 |
---|---|
overriding, overloading 차이점 (0) | 2019.05.29 |
스프링 입문을 위한 자바 객체 지향의 원리와 이해 -1장 (0) | 2019.05.28 |
TechStudty -03 HTTP 프로토콜이란? (0) | 2019.03.11 |
TechStudy - 01.OOP란 ? (0) | 2019.03.06 |