StringJoiner, StringBuilder 정리

2024. 5. 18. 13:11개발노트

실무에서 관습적으로 StringBuilder를 사용해 구분자를 처리하는 로직을 보고 StringJoiner로 리팩터링을 진행하며 관련 내용을 정리한다.

 

 

StringBuilder

StringBuilder는 문자열을 연결할 때 사용하며

구분자를 추가 할 때 아래와 같이 사용한다.

StringBuilder builder = new StringBuilder();
builder.append("Hello");
builder.append(",");
builder.append("World");
String result = builder.toString(); // "Hello,World"

 

 

StringJoiner

StringJoiner는 내부에서 StringBuilder를 사용해 문자열과 문자열을 구분자로 연결하는 작업을 하며

구분자를 추가 할 때 아래와 같이 사용한다.

StringJoiner joiner = new StringJoiner(",");
joiner.add("Hello");
joiner.add("World");
String result = joiner.toString(); // "Hello,World"

 

벤치마크

StringJoiner는 불필요한 구분자 추가 코드가 필요 없어 코드가 깔끔해진다. 하지만 구분자를 추가하는 후처리 작업을 해주기 때문에 성능은 떨어진다.

StringBuilder의 경우 구분자를 모두 append()로 추가해줘야 하기 때문에 코드가 불필요하게 길어 질 수 있지만 후처리 작업 없이 문자열 그대로를 사용하므로 성능이 좋다.

 

아래는 StringBuilder와 StringJoiner의 처리 속도 비교를 위한 밴치마크 코드이다.

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

import java.util.StringJoiner;
import java.util.function.Supplier;

public class 문자열벤치마크테스트 {

    @Test
    public void stringBuilder벤치마크테스트() {
        int 반복횟수 = 100000;
        int 실행횟수 = 10;

        long stringBuilder평균시간 = 벤치마크(실행횟수, () -> {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 반복횟수; i++) {
                sb.append("테스트").append(i);
            }
            return sb;
        });

        System.out.println("StringBuilder 평균 시간: " + stringBuilder평균시간 + " ns");
        assertTrue(stringBuilder평균시간 > 0); // 시간 측정이 제대로 되었는지 확인
    }

    @Test
    public void stringJoiner벤치마크테스트() {
        int 반복횟수 = 100000;
        int 실행횟수 = 10;

        long stringJoiner평균시간 = 벤치마크(실행횟수, () -> {
            StringJoiner sj = new StringJoiner(", ");
            for (int i = 0; i < 반복횟수; i++) {
                sj.add("테스트" + i);
            }
            return sj;
        });

        System.out.println("StringJoiner 평균 시간: " + stringJoiner평균시간 + " ns");
        assertTrue(stringJoiner평균시간 > 0); // 시간 측정이 제대로 되었는지 확인
    }

    private long 벤치마크(int 실행횟수, Supplier<?> 작업) {
        long 총시간 = 0;

        for (int j = 0; j < 실행횟수; j++) {
            long 시작시간 = System.nanoTime();
            작업.get();
            long 종료시간 = System.nanoTime();
            총시간 += (종료시간 - 시작시간);
        }

        return 총시간 / 실행횟수;
    }
}

StringBuilder 평균 시간: 4508579 ns (약 4.5초)
StringJoiner 평균 시간: 6739203 ns (약 6.7초)

 

StringBuilder가 StringJoiner보다 평균 약 1.49배(6,739,203 나노초를 4,508,579 나노초로 나눈 값) 더 빠른 것을 알 수 있다.