ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 🔗 Java 문자열와 구분자
    ☕️ java 2023. 10. 30. 15:56

     

     

    우아한테크코스의 프리코스 자동차 경주 게임 미션에 아래와 같은 요구사항이 있었다.

    • 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다.
    • 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다.

     

    이렇게 문자열을 연결해야하는 요구사항에 대해 해결하고자 여러 방법을 찾아보았다.

     

    🧩 StringBuilder


    ⚠️ String + 연산의 문제

    자바에서 String은 불변이라 문자열에 대해 수정을 할 수 없다.

    String str1 = "abc";
    String str2 = "def";
    String resulta = str1 + str2; // abcdef

    위와 같은 코드가 있을 때, 자바에서는 str1의 길이 + str2의 길이를 가지는 새로운 String을 만들어 낸다.

    따라서, 여러 String을 연결하는데 String의 + 연산을 사용하게 되면 새로운 String을 계속해서 생성해내고 이에 걸리는 시간도 매우 오래 걸린다.

     

    이런 문제를 해결하고자 StringBuilder를 사용해보았다.

     

    💡 StringBuilder

    자바에서는 StringBuilder 클래스를 제공해 String + 연산에 대해 빠르고 효율적으로 처리할 수 있도록 한다.

     

    - StringBuilder는 불변이 아니고 미리 일정한 크기의 배열을 잡아 거기에 String 값을 붙여나가는 방식이다.

     

    🆚 비교

    JMH를 이용해 아래 코드에 대한 성능을 비교해보았다.

    @State(Scope.Benchmark)
    public class Sample {
    
        private static final int N = 1000;
        @Benchmark
        public void testStringBuilder(Blackhole blackhole) {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < N; i++) {
                stringBuilder.append(String.valueOf(i));
            }
        }
    
        @Benchmark
        public void testString(Blackhole blackhole) {
            String str = "";
            for (int i = 0; i < N; i++) {
                str += String.valueOf(i);
            }
        }
    }

        - StringBuilder를 사용한 경우 더 좋은 성능을 보여준다.

    🧑🏻‍💻 실제 코드 작성

    StringBuilder를 통해 요구사항을 처리한 코드

    StringBuilder stringBuilder = new StringBuilder();
    for(String winner : winnerList) {
        stringBuilder.append(winner);
        stringBuilder.append(", ");
    }
    stringBuilder.delete(stringBuilder.length() - 2, stringBuilder.length());

     

    🤩 StringJoiner


    StringJoiner는 Java 8에서 java.util.package 에 추가된 새로운 기능이다.

    • 구분 기호, 접두사, 접미사를 사용해 문자열을 연결하는데 사용할 수 있다.

     

    🧪 test

    @Test
    public void whenAddingListElements_thenJoinedListElements() {
        List<String> fruitList = new ArrayList<>();
        fruitList.add("Apple");
        fruitList.add("Banana");
        fruitList.add("Peach");
    
        StringJoiner fruitJoiner = new StringJoiner(",");
    
        for (String fruit : fruitList) {
    	    fruitJoiner.add(fruit);
        }
    
        assertEquals(fruitJoiner.toString(), "Apple,Banana,Peach");
    }

     

    🧑🏻‍💻 요구사항에 대해 StringJoiner를 적용한 코드

    List<String> winnerList = new ArrayList<>();
    
    StringJoiner joiner = new StringJoiner(", ");
    winnerList.forEach(joiner::add);

    🔥 구분자를 사이사이에 붙여주어 코드가 훨씬 줄어들 수 있었다.

    • StringBuilder를 사용했을 때 보다 더 깔끔하게 코드를 작성할 수 있게 되었다.

     

     

    📍 StringJoiner는 Stream API를 이용해서 더 간결하게 작성할 수 있다.

    // Collectors.joining() 사용
    List<String> winnerList = new ArrayList<>();
    String winnerResult = winnerList.stream().collect(Collectors.joining(", "));
    • Collectors.joining()는 내부적으로 StringJoiner를 사용해 조인 작업을 수행한다.

     

     

    📍 Collectors

    // Collectors 
    public final class Collectors {
        ...
    
        public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
            return joining(delimiter, "", "");
        }
    
        ...
    
        public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
                                                                 CharSequence prefix,
                                                                 CharSequence suffix) {
            return new CollectorImpl<>(
                    () -> new StringJoiner(delimiter, prefix, suffix),
                    StringJoiner::add, StringJoiner::merge,
                    StringJoiner::toString, CH_NOID);
        }
        ...
    }
    • joining 함수를 보면 StringJoiner를 사용하고 있다.

     

    📌 String.join()

    String.join()StringJoiner와 비슷하게 문자열 사이에 구분자를 넣어준다.

    StringJoiner와 다른점은 접두사와 접미사를 넣어주는 작업은 하지 않는다.

     

     

    String.join()을 사용한 경우

    String winnerResult = String.join(", ", winnerList);
    

    이번 미션에서는 간단하게 콤마(,)를 사이에 넣어 문자열을 연결하는 간단한 요구사항이므로 String.join()을 사용했다.

     

    📖 참고자료

    Java 8 StringJoiner | Baeldung

    Concatenating Strings in Java | Baeldung

    ☕ 자바 String / StringBuffer / StringBuilder 차이점 & 성능 비교

    Performance Comparison Between Different Java String Concatenation Methods | Baeldung

    '☕️ java' 카테고리의 다른 글

    ArrayDeque  (0) 2024.03.15
    👻 Mockito  (0) 2023.10.31
    Multiple Assertions  (1) 2023.10.29
    ☕️ Java 17  (1) 2023.10.25
    🆚 AssertJ과 JUnit 의 Assertions 비교  (1) 2023.10.25

    댓글

Designed by Tistory.