본문 바로가기

JAVA

[Snack Java] 3. 자바의 문자열 클래스: 심화(StringTokenizer, StringBuilder, StringBuffer)

2022.05.31 - [JAVA] - [Snack Java] 1. 자바의 타입(Type of JAVA)

2022.05.31 - [JAVA] - [Snack Java] 2. 자바의 문자열 클래스(String Class)

 

문자열을 다루기 위해 만들어진 클래스를 알아봤으니 조금 더 심화적인 String 클래스를 확인해보자.

 

문자열 하나를 다루는데 이런 특수한 클래스들이 생긴 이유는 JAVA의 문자열이 불변성을 가지고 있기 때문이다. Java에서 문자열 한번 값이 할당되면 메모리 공간이 변하지 않는다. 다시 말해 String의 경우 변경, 삽입을 할 때마다 새로운 곳에 데이터를 저장하는 방식으로 연산을 한번 할 때마다 주소값이 바뀐다는 것이다.

 

이런 비효율성을 개선하기 위해 등장한 클래스가 이 심화 클래스들이다. StringTokenizer, Stringbuilder, StringBuffer 클래스는 이미 값이 할당되어 있더라도 한번 더 다른 값이 할당되면 할당된 공간이 늘어나거나 줄어든다. 이렇게 할당된 공간이 변하는 특성을 가리켜 가변성(mutable)이라고 한다.

참고로 이 심화적인 클래스들은 반드시 클래스에 맞는 라이브러리를 임포트(import)해주어야 한다. 

1. StringTokenizer 클래스 (import java.util.StringTokenizer)

StringTokenizer 클래스는 문자열을 우리가 지정한 구분자로 문자열을 쪼개주는 클래스이다. 쪼개진 문자열을 토큰(token)이라고 부른다.

 

StringTokenizer 선언 방법은 문자열 선언 방법과 같다.

StringTokenizer tokenizer = new StringTokenizer();

 

사실 문자열 클래스를 공부한 사람들은 알겠지만, 문자열 자체를 기준에 따라 나누는 메소드가 있기 때문에 이게 굳이 필요할까 생각은 들지만, 일단 편리하고 빠른건 확실하다. 아직 개념이 약간 이해가 안간다면 아래 예시를 보자.

 

import java.util.StringTokenizer;


public class main
{   
    public static void main(String[] args){
        //문자열 선언
	String str = "This is a test";
	StringTokenizer tokenizer = new StringTokenizer(str);
	System.out.println(str); // This is a test
	System.out.println(tokenizer.nextToken()); //This
    System.out.println(tokenizer.nextToken()); //is
    System.out.println(tokenizer.countTokens()); //2
   
    }
}

 

StringTokenizer의 메소드 사용 결과이다. 첫 번째 nextToken()메소드는 "This is a Test"에서 첫 번째 토큰인 "This"를 반환한다. 그런데 한 번 더 같은 메소드를 쓰자 두 번째 토큰인 "is"가 반환된다. 이렇게 메소드로 조작하면서 토큰을 순회한다. 만약 토큰을 다 쓴 상황에서 또 메소드를 쓰게 되면 에러가 발생하게 된다. 

 

countTokens()는 쓰고 남은 토큰의 개수를 반환한다. 따라서 "a", "test"가 남은 현 상황에서는 2를 반환하는 것이다.  

 

StringTokenizer 클래스에 대한 자세한 설명과 메소드를 참고하자.

 

https://docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html

 

StringTokenizer (Java Platform SE 7 )

Constructs a string tokenizer for the specified string. All characters in the delim argument are the delimiters for separating tokens. If the returnDelims flag is true, then the delimiter characters are also returned as tokens. Each delimiter is returned a

docs.oracle.com

 

2. StringBuilder 클래스 (import java.lang.StringBuilder)

StringBuilder 클래스는 문자열을 합쳐주는 클래스이다. 물론 더하기 연산자로도 문자열을 합칠 수 있지만 여러번의 반복 작업이 필요한 경우나 다양한 타입의 데이터를 더하는 경우에 쉽게 사용할 수 있으며 문자열을 합치기 위한 다양한 메소드를 제공한다.

 

선언방법

 

StringBuilder stringBuilder = new StringBuilder();

 

다음은 StringBuilder의 예시이다. 유의해야 할 점은 우리가 StringBuilder를 사용하는 이유는 문자열로 출력하고자 함이므로 마지막에 toString()메소드를 이용해 문자열로 바꿔주는 작업이 필요하다는 것이다. 각종 메소드를 활용해 문자열을 요리하는 코드이다.

 

import java.lang.StringBuilder;


public class main
{   
    public static void main(String[] args){
        //StringBuilder 선언
        StringBuilder stringBuilder1 = new StringBuilder();
        
        //문자열끼리 붙이기
        stringBuilder1.append("피카츄").append(" 라이츄");
        System.out.println(stringBuilder1.capacity());  //16 -> 저장용량 확인 메소드
        String str1 = stringBuilder1.toString();
        System.out.println(str1); // 피카츄 라이츄
        System.out.println(stringBuilder1.delete(2, 5));  //피카이츄 -> 인덱스 사이 문자열 삭제 메소드
        System.out.println(stringBuilder1.replace(2, 4, "츄이")); //피카츄이 -> 인덱스 사이 문자열 변경
        System.out.println(stringBuilder1.insert(2, "꼬부기")); //피카꼬부기츄이 -> 인덱스 위치에 데이터 삽입

        StringBuilder stringBuilder2 = new StringBuilder();
        
        //다양한 타입 붙이기
        stringBuilder2.append('c').append(1.1).append(12.7184f).append(9044212740918405282L);
        String str2 = stringBuilder2.toString();
           
        System.out.println(str2);     


    }
}

 

 

Stringbuilder 클래스의 자세한 설명과 메소드를 보자

https://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html

 

StringBuilder (Java Platform SE 7 )

Inserts the string into this character sequence. The characters of the String argument are inserted, in order, into this sequence at the indicated offset, moving up any characters originally above that position and increasing the length of this sequence by

docs.oracle.com

 

3. StringBuffer 클래스 (import java.lang.StringBuffer)

String 클래스의 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수 없다. StringBuffer 클래스의 인스턴스는 그 값을 변경할 수도 있고, 추가할 수도 있다. 덧셈 연산자를 사용하여 인스턴스 안에 있는 내용을 더하고 뺄 수 있지만 그건 기존 인스턴스의 메모리를 삭제하고 재생성하는 과정이다.

 

만약 덧셈(+) 연산자를 이용해 String 인스턴스의 문자열을 결합하면, 내용이 합쳐진 새로운 String 인스턴스를 생성한다. 따라서 문자열을 많이 결합하면 결합할수록 공간이 낭비될 뿐만 아니라 속도 또한 매우 느려지게 되는 불상사가 일어난다. StringBuffer 인스턴스를 사용하면 문자열을 바로 추가할 수 있으므로, 공간의 낭비도 없애고 속도도 매우 빨라진다.

 

StringBuffer 클래스는 값의 쉬운 추가 변경을 위해 내부적으로 버퍼(buffer)라고 하는 독립적인 공간을 가지고 있다. 버퍼 크기의 기본값은 16개의 문자를 저장할 수 있는 크기이며, 그 크기를 별도로 설정할 수도 있다. 물론 똑똑하게도인간을 믿지 않아(...) 인스턴스 생성 시 사용자가 설정한 크기보다 언제나 16개의 문자를 더 저장할 수 있도록 여유 있는 크기로 생성된다. 

 

일단 선언 방법부터 보자

StringBuffer str = new StringBuffer("Java");

 

이제 메소드를 조금 볼텐데 앞서 배운 StringBuilder와 거의 명령어가 같다.

 

import java.lang.StringBuilder;


public class main
{   
    public static void main(String[] args){
        
        //StringBuffer 선언
        StringBuffer str = new StringBuffer("고우스트");
        System.out.println("포켓몬 이름 : " + str); // 포켓몬 이름 : 고우스트
        System.out.println(str.append("가 진화하면?")); // 고우스트가 진화하면?
        System.out.println(str.insert(11, " 팬텀!")); // 고우스트가 진화하면? 팬텀!
    }
}

 

StringBuilder와 StringBuffer의 사용성이 거의 같은데 이렇게 나누어진 이유가 뭘까?

바로 동기화 방식 차이에 의한 차이이다. 이를 알기 위해서는 쓰레드(thread)에 대한 지식이 필요한데 지금은 당장 알 필요가 없으니 넘어가자. 결론만 말하지면 StringBuffer가 멀티쓰레드 환경, StringBuilder가 단일쓰레드 환경에서 유리하다. 

 

 

스트링 버퍼에 대한 메소드와 설명이다.

 

https://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html

 

StringBuffer (Java Platform SE 7 )

Inserts the string into this character sequence. The characters of the String argument are inserted, in order, into this sequence at the indicated offset, moving up any characters originally above that position and increasing the length of this sequence by

docs.oracle.com