티스토리 뷰

Java/Class

3. StringBuffer & StringBuilder

알 수 없는 사용자 2018. 10. 18. 02:46


이번 포스팅에서는

String 클래스의 단점을 보완한

StringBuffer 클래스와 StringBuilder 클래스를

다루어 보도록 하겠습니다.


===============================================


StringBuffer & StringBuilder




1. StringBuffer & StringBuilder : What?


 StringBuffer와 StringBuilder는 서로 매우 유사한 특징을 가지고 있습니다. 다만 한가지 특징이 다를 뿐 나머지 기능은 완전히 똑같은 기능을 합니다.

두 클래스는 모두 변경이 가능한 String 객체라고 생각하시면 됩니다. 내부적으로 문자열을 바꾸기 위한 버퍼를 가지고 있고, 클래스의 인스턴스를 생성할 때 크기를 지정할 수 있습니다.


String의 경우 immutable 클래스라고 했었습니다. 그렇기 때문에 + 연산자를 통해 String 객체를 더할 때 문자열이 합쳐진 새로운 인스턴스가 생성되면서 반환되는 것이라 했습니다. 





 이러한 메모리 효율 측면에서 단점을 가진 String 클래스를 보완한 것이 StringBuffer와 StringBuilder 입니다.

이 두 클래스는 String과 같이 char[]의 value 값을 변수로 가지고 있습니다.

public final class StringBuffer implements java.io.Serializable {
private char[] value;
...
}



String과 다르게 char[]의 사이즈는 문자열의 크기만큼이 아니라 문자열을 저장하고 편집하기 위한 공간(Buffer)이 여유 있게 생성됩니다.

만일 문자열이 추가되어 버퍼 공간보다 커질 경우 기존에 있던 배열의 내용을 다시 적당한 크기의 버퍼를 생성하여 붙여넣습니다. 

이렇게 함으로써 StringBuffer 클래스의 인스턴스변수 value는 길이가 증가되고 문자열이 추가된 배열을 참조하게 됩니다. 

...
char newValue[] = new Char[newCapacity];

System.arraycopy(value,0,newValue,0,count);
value =newValue;



결국 쉽게 말해 String 객체 내부에서 배열을 조절하여 값을 참조함으로 문자열이 더해져도 새로운 String 객체를 생성할 필요가 없어지는 것입니다.







2. StringBuffer & StringBuilder : Difference ?


 StringBuffer와 StringBuilder의 차이는 멀티쓰레드의 안전 여부에 있습니다. 

아직 쓰레드에 대해 공부하지 않았기 때문에 자세한 설명은 하지 않겠습니다.

다만, 동기화가 StringBuffer의 성능을 떨어뜨리는 것만 알고 넘어가면 될 것 같습니다. 

그래서 StringBuffer에서 동기화만 뺀 StringBuilder 클래스가 만들어진 것인데 StringBuffer의 성능도 충분히 좋아 반드시 필요한 경우가 아니라면 StringBuffer를 사용해도 좋습니다.





3. StringBuffer & StringBuilder : When, Why?


 두 클래스는 String에 비해 문자열을 더할 때 성능상 우위에 점할 수 있습니다. 만들어진 목적도 이것입니다.

특히 우리가 나중에 데이터베이스를 통해 복잡한 프로그램을 만든다면 SQL 문을 많이 쓰면서 문자열 연산을 하게 될 텐데 이럴 경우 문자열 연산이 많아질수록 성능의 차이는 더 심해질 것입니다.

 그런데 사실 JDK 1.5버전 이후에는 String객체를 사용하더라도 컴파일러가 자동으로 StringBuilder로 바꿔서 처리해주기 때문에 String 클래스를 활용하더라도 성능상의 큰 차이는 없어졌습니다.

 하지만 그래도 문자열이 더해지는 작업이 많을수록 객체를 계속 추가한다는 사실에는 변함이 없습니다. 그렇기 때문에 문자열을 더하는 작업이 많다고 판단된다면 StringBuilder나 StringBuffer 클래스를 쓰는 것이 좋습니다.


 또한 StringBuilder와 StringBuffer에서 고민하신다면 스레드와 관련이 있으면 StringBuffer를, 스레드 안전 여부와 상관없다면 StringBuilder를 사용하는 것이 좋습니다.





4. StringBuffer & StringBuilder : How?


 StringBuffer와 StringBuilder의 생성자는 이름만 다를 뿐 기능은 동일하기 때문에 StringBuffer로 진행하겠습니다.


[StringBuffer의 생성자]


StringBuffer인스턴스를 생성할 때는 문자열, 버퍼 크기, CharSequence, 기본 생성자로 생성할 수 있습니다.

기본 생성자로 생성할 시 버퍼의 크기를 16으로 생성해줍니다.

만약 문자열로 StringBuffer를 생성한다면 전달된 문자열에 편집할 문자열의 길이를 고려하여 +16 만큼의 버퍼 크기를 생성하고 문자열을 저장합니다.



public class Source06_StringBuilder {
public static void main(String[] args) {
    // StringBuilder sb = new StringBuilder();      // 기본 생성자
    // StringBuilder sb = new StringBuilder(30);      // int : char[]크기 설정
         StringBuilder sb = new StringBuilder("String"); // String : char[]에 해당 문자열 올림
        System.out.println(sb.length());             // StringBuilder에 생성된 문자열의 길이 / 0
         System.out.println(sb.capacity());            // 문자열을 생성하기 위해 생성한 char[]의 크기 / default : 16
}
}

위 코드를 입력하고 각 생성자마다 주석을 풀고 실행해보시면 됩니다.



String과 달리 StringBuffer와 StringBuilder에는 equals 메소드가 오버라이드 되어있지 않습니다.

때문에 만약 StringBuffer나 StringBuilder의 두 객체에 들어있는 문자열을 비교하고 싶다면 equals 메소드를 오버라이딩하여 재정의 해주어야 합니다.





5. StringBuffer & StringBuilder : Method?


String과 관련된 클래스이기 때문에 실제로 많은 기능이 비슷합니다.

다만, 문자열을 추가하고 삭제, 변경과 같이 저장된 내용을 변경할 수 있는 메소드들이 추가로 존재합니다.


public class Source07_StringBuilder {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("JavaProgramming"); // String 객체 생성, toCharArray()를 통해 char[]에 복사
char c = sb.charAt(4);            // String 기능을 똑같이 사용
System.out.println(c);            // P

sb.delete(3, 6);              // 1~3까지의 char[]을 지움 (이후의 char[]의 값을 비어있는 인덱스로 땡김)
System.out.println(sb.toString()); // Javoogramming
sb.deleteCharAt(0);          // 해당 인덱스 문자 삭제
System.out.println(sb.toString()); // avogramming

sb.insert(5, "BAAAM!");         // 해당 인덱스에 문자열 삽입
System.out.println(sb.toString()); // avogrBAAAM!amming

sb.replace(0, 4, "?");             // 0~3번까지의 문자열을 ?로 바꿈.
System.out.println(sb.toString() + " / " + sb.length()); // ?rBAAAM!amming / 14

sb.setCharAt(5, '#');             // 해당 인덱스에 문자만 교체
System.out.println(sb.toString() + " / " + sb.length()); // ?rBAA#M!amming / 14

StringBuilder sbb = sb.reverse(); // 문자열의 순서를 변환하여 자기 자신의 객체 리턴
System.out.println(sb.toString() + " / " + sb.length()); // gnimma!M#AABr? / 14

System.out.println(sbb == sb); // true (거의 모든 기능의 반환값이 자기 자신의 객체를 리턴하기 때문에 같은 객체로 인식)

sb.reverse().insert(3, "12345").reverse(); // 자기 자신의 객체를 반환하는 특징을 이용해 작업을 이어서 설계가능.
System.out.println(sb.toString());   // gnimma!M#AA54321Br?
}
}



- append() :

  StringBuilder나 StringBuffer에 문자열을 더하는 메소드입니다. 반환형으로는 자기 자신의 객체를 반환합니다.

 이 메소드의 특징은 String형뿐만 아니라 다른 데이터 타입도 받을 수 있습니다. 타입으로 전달된 문자를 그대로 문자열로 변환하여 더해주는 것입니다.

- capacity() : 

  현재 설정된 버퍼의 크기를 int형으로 반환해줍니다.

- charAt() :

 String 클래스와 같이 해당 인덱스의 문자를 char형으로 반환해줍니다.

- delete() :

 인자로 시작 인덱스와 끝 인덱스를 전달하여 범위 내의 문자열을 삭제하고 자신의 객체를 반환합니다. (문자열에서 범위가 나올 시 이상~미만입니다.)

- insert() :

 append()에 인덱스를 응용한 메소드로 해당 인덱스에 문자를 끼워 넣을 수 있고 자신의 객체를 반환합니다. append()와 마찬가지로 어떤 타입이든 인자로 전달 가능합니다.

- length() :

 현재 객체에 들어있는 문자열의 길이를 int형으로 반환합니다.





'Java > Class' 카테고리의 다른 글

5. Wrapper Class  (0) 2018.10.22
4. 정규표현식(Regular Expression) : java.util.regex 패키지  (0) 2018.10.19
2. String Class  (0) 2018.10.17
1. Object Class  (0) 2018.10.16
0. APIs & Class  (0) 2018.10.16
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함