본문 바로가기
프로그래밍/Java

[Java 8] Java 8, Stream의 Collectors

by 사바라다 2019. 11. 29.

안녕하세요. 이전 시간에 우리가 Stream에 대해서 알아봤던 것 기억하시나요? 오늘은 이어서  Collectors에 대해서 이야기 해보려고 합니다. Collectors란 "Stream을 일반적인 List, Set등으로 변경시키는 Stream 메서드"라고 입니다. 오늘은 Collectors를 통해 어떤 형태로 변경할 수 있는지에 대해서 알아보겠습니다.

오늘 수고해줄 List는 아래의 String List입니다.

List<String> givenList = Arrays.asList("a", "bb", "cc", "bb");

그렇다면 위의 메서드를 이용하여 한번 Stream을 Collectors로 다뤄보도록 하겠습니다.

toCollections

toList, toSet

toList collector는 모든 Stream elements를 List나 Set instance로 변경하는 메서드입니다. 중요한 것은 특정한 Collection으로 변환이 되는것은 아니라는 것입니다. LinkedList로 할 수 있고 그런게 아니라는 거지요. 좀 더 정밀한 컨트롤을 하고싶다면 toCollection을 사용하면 됩니다.

List<String> result = givenList.stream().collect(Collectors.toList()); // a, bb, ccc, dd
Set<String> result = givenList.stream().collect(Collectors.toSet()); // a, bb, ccc

toCollection

toCollection 메서드를 이용하여 면 특정한 Collection으로 implementation이 가능합니다. 아래는 Stream 요소들을 LinkedList로 변환하는 방법입니다.

givenList.stream().collect(Collectors.toCollection(LinkedList::new));

toMap

toMap collector는 Stream elements들을 Map instance로 변경하는 메서드입니다. keyMapper, valueMapper를 이용하여 처리할 수 있습니다. toMap(keyMapper, valueMapper)의 형태를 띄게 됩니다. 예를 한번 들어보겠습니다.

Map<String, Integer> result = givenList.stream().collect(toMap("key", String::length);

이렇게 예제를 구성해 보겠습니다. key라는 이름의 key에 4가지의 elements가 들어가기 때문에 key 충돌이 발생할 것입니다. 이떄 위의 경우는 IllegalStateException가 발생합니다. key 중복이라는 의미입니다. key 중복시 처리방법은 아래와 같이 설정해야합니다.

Map<String, Integer> result = givenList.stream()
  .collect(toMap("key", String::length, (old, new) -> old));

item은 기존에 들어있던 value이며 identicalItem은 key 중복으로 들어온 value입니다. 이때에는 기존의 값을 사용하겠다고 명시하였습니다.

collectingAndThen

CollectingAndThen 메서드는 Collecting을 진행한 후 그 결과로 메서드를 하나 더 호출 할 수 있게 해줍니다.

System.out.println(givenList.stream().collect(collectingAndThen(toList(), Collection::toString)));

위의 예제는 stream을 toList로 만들고 elements를 출력할 수 있는 형태로 만든 것을 println으로 찍어보는 예제입니다. 이때의 givenList.stream().collect(collectingAndThen(toList(), Collection::toString))의 return 값은 collectionAndThen의 뒤의 function의 return값에 따라값니다.

joining

joining은 Stream을 List가 아닌 String으로 붙여주거나 할 때 사용하는 메서드입니다.

String result = givenList.stream().collect(joining()); // abbcccdd

joining에 파라미터로 연결 부분에 들어갈 문구를 정할 수 있습니다. 만약 joining(",") 이라고 하면 a,bb,ccc,bb 이렇게 출력됩니다.

String result = givenList.stream()
  .collect(joining(" ", "PRE-", "-POST"));

이렇게 사용하면 PRE-a bb ccc dd-POST 이런식으로 출력을 기대할 수도 있습니다.

counting

elements의 수를 세는 것입니다.

Long result = givenList.stream().collect(counting());

groupingBy

database를 조작할 때나 사용하던 group by를 Collection으로 사용할 수 있습니다.

Map<Integer, List<String>> result = givenList.stream()
  .collect(groupingBy(String::length, toList()));

  // 1, a
  // 2, bb bb
  // 3, ccc

이를 응용해서 제작한 filtering되는것은 true, 되지 않는것은 false로 묶어주는 partitioningBy 등이 있습니다.

마무리

오늘은 이렇게 해서 Collector에 존재하는 여러 메서드들에 대해서 알아보고 사용해보았습니다.

예전에 책을 보다가 이런말을 본적이 있습니다.

기계가 이해하는 코드는 누구든 짤 수 있지만 사람이 이해하기 쉬운 코드는 아무나 짤 수 있는게 아니다.

코드가 간결할 필요가 뭐가있나라고 생각할 수 있습니다. 하지만 내가 만든 코드를 나만보는게 아니라는 마음가짐으로 다가가면 충분히 이해할 수 있을거라 생각합니다.

감사합니다.

참조

https://www.baeldung.com/java-8-collectors

댓글