클로이의 데이터 여행기

[JAVA] 문자열 연결 처리 속도 높이기 본문

JAVA

[JAVA] 문자열 연결 처리 속도 높이기

징느K 2019. 2. 7. 07:58

 

이번 포스팅에서 살펴볼 내용은 '문자열 연결 처리 속도를 높이는 방법'입니다.

다양한 문자열(Stirng, StringBuffer,StringBuilder, StringJoiner) 선언 방법과 특징은 이전 포스팅(https://data-traveler.tistory.com/21)에서 다루었으니 참고부탁드립니다.

앞선 포스팅에서 말씀드렸던 것처럼, 문자열 연결을 할 때, String 선언 후 +연산자를 활용하여 문자열을 연결하는 방법 보다는 StringBuffer,StringBuilder등으로 선언 후  append메서드로 문자열을 축적하는 방법이 처리속도를 높이는데는 효과적이라고 알려져있는데요. 실제로 속도차이가 얼마나 나는지 테스트해보고, 문자열 메소드별 활용방법에 대해 알아보려고 합니다.

 

1. 테스트 코드 작성 및 결과확인

문자열 메소드 별 속도 및 활용처를 알아보기 위하여 아래와 같이 코드를 작성해보았습니다. 

 

(1) 테스트 코드 작성

① 분석데이터 셋팅

: 동일한 데이터를 활용하여 속도테스트를 하기 위해 아래와 같이 전역변수로 데이터를 셋팅하였습니다. 

(참고로 테스트 코드는 빵,과일,음료 리스트를 조합하여 조식리스트를 조합하는 코드입니다*_*)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package posting;
 
import java.util.StringJoiner;
 
public class connectString {
    static String[] bread = { "크로와상""어니언베이글""치즈베이글""블루베리베이글""우유식빵""모닝빵""앙버터브레드""애플파이""뺑오쇼콜라""포카치아",
            "모카번""코요타""바게트""초코머핀""브라우니" };
    static String[] fruit = { "사과""딸기""포도""수박""체리""천도복숭아""키위""메론""참외""청포도""자두""바나나""파인애플""살구",
            "감""구아바""앵두""귤""오렌지""망고""여주""블루베리""무화과""매실""블랙베리""머루""금귤""석류""모과""대추""애플망고",
            "샤인머스캣""황도" };
    static String[] drink = { "오렌지주스""카페라떼""아메리카노""카푸치노""사과주스""플레인요거트""요쿠르트""플렛화이트""감귤주스""청포도에이드",
            "한라봉주스""복숭아에이드""레몬에이드""페퍼민트티""자스민티""국화차""녹차""홍차" };
    static String comma = ",";
}
 
cs

 

String 선언 후, +연산자 활용

: 가장 간단히 문자열을 연결하는 방법이지만, 성능이 좋지 않다고 알려져있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
    public static void connectByPlus() {
 
        for (int n = 0; n < bread.length; n++) {
            for (int j = 0; j < fruit.length; j++) {
                System.out.println("==================Plus==================");
                for (int m = 0; m < drink.length; m++) {
                    System.out.println("[ " + bread[n] + comma + fruit[j] + comma + drink[m] + " ]");
                }
            }
        }
    }
 
cs
 

③ StringBuilder 선언 후, append 메서드 활용

: 연산 시, 성능이 가장 높은 클래스로 알려져있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void connectByStringBuilder() {
        for (int n = 0; n < bread.length; n++) {
            for (int j = 0; j < fruit.length; j++) {
                System.out.println("==================StringBuilder==================");
                for (int m = 0; m < drink.length; m++) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("[ ");
                    sb.append(bread[n]);
                    sb.append(comma);
                    sb.append(fruit[j]);
                    sb.append(comma);
                    sb.append(drink[m]);
                    sb.append(" ]");
                    String resultString = sb.toString();
                    System.out.println(resultString);
                }
            }
        }
    }
cs

 

④ StringBuffer 선언 후, append 메서드 활용

: 가장 안정적인 클래스로 알려져있습니다. (스레드에 안전함)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void connectByStringBuffer() {
        for (int n = 0; n < bread.length; n++) {
            for (int j = 0; j < fruit.length; j++) {
                System.out.println("==================StringBuffer==================");
                for (int m = 0; m < drink.length; m++) {
                    StringBuffer sb = new StringBuffer();
                    sb.append("[ ");
                    sb.append(bread[n]);
                    sb.append(comma);
                    sb.append(fruit[j]);
                    sb.append(comma);
                    sb.append(drink[m]);
                    sb.append(" ]");
                    String resultString = sb.toString();
                    System.out.println(resultString);
                }
            }
        }
    }
cs

 

StringJoiner 선언 후, add 메서드 활용

: 자바8에서 추가된 클래스입니다. 구분자,접두사,접미사를 처리하기에 용이하다는 장점을 가지고 있습니다. 

( *(3),(4)번과 (5)번에서 대괄호("[","]")와 구분자(",")를 어떻게 넣었는지 비교해보시면 될 것 같습니다. )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void connectByStringJoiner() {
        for (int n = 0; n < bread.length; n++) {
            for (int j = 0; j < fruit.length; j++) {
                System.out.println("==================StringJoiner==================");
                for (int m = 0; m < drink.length; m++) {
 
                    // StringJoiner (구분자,접두사,접미사)의 형태로 작성!
                    StringJoiner sj = new StringJoiner(",""[ "" ]");
                    sj.add(bread[n]);
                    sj.add(fruit[j]);
                    sj.add(drink[m]);
                    String resultString = sj.toString();
                    System.out.println(resultString);
                }
            }
        }
    }
cs

 

속도 측정 및 결과 출력

: 속도 측정은 메소드별 시작시간과 종료시간을 기록하는 방식으로 측정하였습니다.

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
public static void main(String[] args) {
 
        long plusStartTime = System.currentTimeMillis();
        connectByPlus();
        long plusEndTime = System.currentTimeMillis();
 
        long builderStartTime = System.currentTimeMillis();
        connectByStringBuilder();
        long builderEndTime = System.currentTimeMillis();
 
        long bufferStartTime = System.currentTimeMillis();
        connectByStringBuffer();
        long bufferEndTime = System.currentTimeMillis();
 
        long joinerStartTime = System.currentTimeMillis();
        connectByStringJoiner();
        long joinerEndTime = System.currentTimeMillis();
 
        System.out.println("==================Result==================");
        System.out.println("[+ 연산자] 소요시간  ==>  " + (plusEndTime - plusStartTime) + "(ms)");
        System.out.println("[builder] 소요시간  ==>  " + (builderEndTime - builderStartTime) + "(ms)");
        System.out.println("[buffer] 소요시간 ==>  " + (bufferEndTime - bufferStartTime) + "(ms)");
        System.out.println("[joiner] 소요시간 ==>  " + (joinerEndTime - joinerStartTime) + "(ms)");
 
    }
cs

 

(2) 결과 확인

위에서 작성된 코드를 분석한 결과는 아래와 같습니다. 처리할 데이터가 많지 않아 소요시간 단위는 밀리세컨드(ms)입니다.

코드를 실행 할 때마다 소요시간이 달라졌지만,  +연산자 보다는 append,add 메서드를 활용하는 방법이 소요시간을 줄일 수 있다는 것을 알 수 있었습니다. 데이터의 양이 많아질 수록 이 차이는 더욱 커질 것이기 때문에 속도 이슈를 고려한다면 'String 선언 후 +연산자를 통한 문자열연결'은 지양하시는 것이 좋겠습니다.

 

[실행 1]

 

[실행 2]

 
 
[실행 3]

 

[실행 4]

 

 

2. 결론

문자열 처리 관련 클래스별 사용방법은 아래와 같습니다. 

상황을 고려하여 적절한 클래스를 활용하여 문자열 처리를 하시면 됩니다.

 

- 문자열 연결이 많을 때, '+' 연산자보다 new연산자를 활용

- 안정적인 개발을 하고자( ex. 스레드(thread)가 불안) 할 때,  StringBuffer를 활용

- 성능이 중요할 때, StringBuilder를 활용

구분자/접두사/접미사를 간편히 사용하고자 할 때, StringJoiner를 활용

 

이상입니다. 읽어주셔서 감사합니다 XD

 

 

Comments