안녕하세요. 오랫만에 뵙겠습니다. 간혹 가다가 백준에서 문제를 풀다 보면, 문자열이 x개 나오면 이 문자열들 사이에 특정 문자를 넣어야 하는 경우가 있습니다. 예를 들어, 테스트 케이스 문제라면 개행 문자를 넣는 경우가 있을 겁니다. python에서는 이러한 기능을 join으로 매우 쉽게 처리할 수 있었어요.

 

 

 예를 들어, 이런 식으로 쓰면 출력은 어떻게 될까요? 아시다시피 'my name is cho'가 출력이 됩니다.

 

 

 사용법도 그리 어렵지 않아요. 그냥 Iterable한 객체를 넘겨주면, separator가 element 사이에 끼어들어가 버리게 됩니다. 저 예제에서는 list를 넘겨주었고, Separator로 ' '을 넘겨주었기 때문에, 원소들 사이에 공백이 하나 들어갑니다.

 

 

 그래서 my name is cho가 출력되게 됩니다.

 


 이와 비슷한 기능을 하는 것이 java에는 없을까요? 공식 문서를 찾아보니 이미 java 8부터 join이라는 메소드가 제공되고 있었습니다.

 

 

 이 메서드를 보시면 static으로 선언이 되어 있고요. delimiter랑 elements를 넘겨버림을 알 수 있어요. 보통 저는 이런 것을 넘길 때, 배열로 많이 처리하는 편입니다.

 

 

 "my", "name", "is", "cho"가 들어있는 String 배열을 넘겼습니다. 그리고 구분자는 공백으로 해 주었어요. 결과는 어떻게 나올까요?

 

 

 놀랍게도 "my name is cho"가 뜨게 됩니다. 어렵지 않네요. 혹은 이렇게 넘기셔도 됩니다.

 

 

 이렇게 코딩하셔도 똑같은 결과가 나옵니다. 저는 보통 배열이나 List를 많이 인자로 넘겨버리는 편입니다. 당연하게도 단순히 해당 원소들을 concat만 시키려면, delimiter로 빈 문자열을 넘겨주시면 됩니다.

 

 

 이 메서드는 파이썬에서만 써 봤지, 자바에서는 써 본 적이 한 번도 없었습니다. 그런데, 앞으로는 자주 써 먹어야 겠습니다.

 


 그러면 이 메서드는 어떻게 동작할까요? 천천히 보겠습니다.

 

 

 먼저, StringJoiner라는 것을 새로 생성한 다음에, elements를 돌면서 joiner에 element에 속한 item을 add 합니다. 딱 보았을 때 joiner는 스트링을 concat 하기 위한 것이라는 게 한눈에 파악이 됩니다. 저는 솔직히 클래스 이름 지을 때 II, JJ, KK 이런 식으로 많이 짓곤 하는데 그게 비하면 한눈에 와 닿습니다.

 

 이 클래스 안에, StringBuilder나 StringBuffer 등이 있을 거 같은 느낌이 드는데요. joiner의 add 메소드가 elements의 길이만큼 호출이 될 테니, add 메소드가 어떻게 동작하느냐에 따라서, join 복잡도가 결정될 겁니다. 안으로 들어가 봅시다.

 

 

 그러면, prepareBuilder()의 리턴값에, append를 한다는 것만 볼 수 있는데요. prepareBuilder를 봅시다.

 

 

 이 메서드를 보니까, StringBuilder를 리턴합니다. 227번째 줄을 보니까 value를 리턴하는 걸로 보아서는, value가 StringBuilder 객체일 겁니다. 처음에 value가 null이라면, 224번째 줄에서 value는 새로운 StringBuilder를 할당하고, prefix를 추가할 겁니다. 단순히 join만 호출한 경우에는 delimeter만 들어가게 되므로, 225번째 줄이 끝난 후에는 다음과 같이 StringBuilder에 들어갑니다.

 

 

 그리고 value가 리턴될 겁니다. 이것을 어디서 쓸까요? StringJoiner의 add 메서드에 prepareBuilder().append(element)가 있었는데요. append를 호출할 때 다시 이 value를 써먹게 됩니다. element가 처음에는 'my' 였으므로 해당 부분이 호출된 후에는 value가 아래와 같이 바뀔 겁니다.

 

 

 다음에 또 add가 호출되면 prepareBuilder가 호출될 겁니다. 이 때, delimeter가 먼저 추가됩니다.

 

 

  그리고 나서 'name'이 append 될 겁니다. 이런 식으로 append가 되기 때문에, 시간 복잡도는 elements 길이만큼 됩니다. 최악의 경우에 제곱에 비례해서 늘어가는 것이 아니고요. Stringbuilder의 append 메소드의 복잡도를 잘 생각해 보시면 좋을 듯 싶습니다.