Java - Stream.collect() 사용 방법 및 예제

Stream.collect()의 사용 방법 및 예제를 소개합니다.

1. Stream.collect()

collect()는 Stream의 데이터를 변형 등의 처리를 하고 원하는 자료형으로 변환해 줍니다.

Collect는 다음과 같은 기능들을 제공합니다.

  • Stream의 아이템들을 List 또는 Set 자료형으로 변환
  • Stream의 아이템들을 joining
  • Stream의 아이템들을 Sorting하여 가장 큰 객체 리턴
  • Stream의 아이템들의 평균 값을 리턴

이 외에 다른 많은 기능들도 제공합니다.

Collect의 기본적인 기능들을 예제와 함께 알아보겠습니다.

2. Stream의 아이템들을 HashSet으로 리턴

Stream.collect()는 Stream의 요소들을 다른 자료형으로 변환합니다.

Stream.collect()는 아래와 같이 3개의 인자를 받고, 이 인자들을 이용하여 Stream의 요소들을 다른 자료형으로 변환합니다.

collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)

아래 예제는 Stream.collect()를 이용하여 Stream의 결과를 HashSet<String>로 리턴하는 코드입니다. HashSet에 대한 Supplier, accumulator, combiner를 collect()의 인자로 전달해주었고 HashSet 객체가 리턴되었습니다.

Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
HashSet<String> fruitHashSet = fruits.collect(HashSet::new, HashSet::add, HashSet::addAll);
for (String s : fruitHashSet) {
    System.out.println(s);
}

Output:

banana
apple
cherry
kiwi
lemon
peach
mango

2.1 Collectors를 이용하여 동일한 내용 구현

위의 코드는 collect에 3개의 params을 넣어야 해서 다소 사용하기 번거롭습니다. Collectors라는 라이브러리가 기본적인 기능들을 제공해주어 이런 불편함을 해결해줍니다.

다음은 Collectors와 함께 collect로 HashSet 객체를 만드는 예제입니다. 인자에 Collectors.toSet()을 넣어주면 Set 자료형으로 만들어 줍니다.

Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
Set<String> fruitSet = fruits.collect(Collectors.toSet());
for (String s : fruitSet) {
    System.out.println(s);
}

Output:

banana
apple
cherry
kiwi
lemon
peach
mango

3. Stream의 요소들을 List로 변환

Collectors를 이용하여 스트림의 요소들을 List 객체로 변환할 수 있습니다.

아래와 같이 Collectors.toList()를 인자에 전달하면 List 객체로 리턴됩니다.

Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
List<String> fruitList = fruits.collect(Collectors.toList());
for (String s : fruitList) {
    System.out.println(s);
}

Output:

banana
apple
mango
kiwi
peach
cherry
lemon

4. Stream 요소를 1개의 String 객체로 변환

Stream의 모든 요소들을 1개의 String으로 만들 수도 있습니다.

아래와 같이 Collectors.joining()을 인자로 넣어주시면 됩니다.

Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
String result2 = fruits.collect(Collectors.joining());
System.out.println(result2);

Output:

bananaapplemangokiwipeachcherrylemon

만약 문자열을 합칠 때 구분자를 넣어주고 싶다면 Collectors.joining(", ")처럼 인자로 넣어주면 됩니다.

Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
String result2 = fruits.map(Object::toString).collect(Collectors.joining(", "));
System.out.println(result2);

Output:

banana, apple, mango, kiwi, peach, cherry, lemon

5. 가장 큰 객체 1개만 리턴

Stream의 아이템들을 어떤 조건으로 비교하여 충족되는 1개의 아이템만 리턴받을 수 있습니다.

다음 코드는 문자열의 길이가 가장 긴 요소를 리턴하는 예제입니다. Optional<String>으로 리턴하며, 문자열 길이를 비교하는 함수(Comparator)는 직접 만들어 인자로 전달하였습니다.

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.maxBy;

Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
Function<String, Integer> getCount = fruit-> fruit.length();
Optional<String> result = fruits.map(Object::toString).collect(maxBy(comparing(getCount)));
System.out.println("result: " + result.orElse("no item"));

Output:

result: banana

6. Collectors로 평균 값 구하기

Collectors는 스트림 아이템들의 평균 값을 구해주는 기능들도 제공합니다.

List<Integer> list = Arrays.asList(1,2,3,4);
Double result = list.stream().collect(Collectors.averagingInt(v -> v*2));
System.out.println("Average: "+result);

Output:

Average: 5.0

7. Custom 객체에 Collect 적용

Custom 객체에 대해서도 Collect를 할 수도 있습니다. Collectors.toMap()을 사용하면 됩니다.

Stream<Fruit> fruits2 = Stream.of(new Fruit("1", "banana"), new Fruit("2", "apple"),
        new Fruit("3", "mango"), new Fruit("4", "kiwi"),
        new Fruit("5", "peach"), new Fruit("6", "cherry"),
        new Fruit("7", "lemon"));
Map<String, String> map = fruits2.collect(Collectors.toMap(Fruit::getId, Fruit::getName));
for (String key : map.keySet()) {
    System.out.println("key: " + key + ", value: " + map.get(key));
}

static class Fruit {
    public String id;
    public String name;

    Fruit(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }
    public String getName() {
        return name;
    }
}

Output:

key: 1, value: banana
key: 2, value: apple
key: 3, value: mango
key: 4, value: kiwi
key: 5, value: peach
key: 6, value: cherry
key: 7, value: lemon

8. toMap() 수행시, 동일한 Key에 대한 예외처리

toMap() 수행 중, 동일한 key를 갖고 있는 데이터를 만나면 IllegalStateException을 발생시킵니다. 이런 경우 예외처리를 할 수 있습니다. 3번째 param으로, 존재하는 값과 새로운 값이 중 어떤 값을 저장할지 정의해야 합니다. 아래 코드는 기존에 등록된 값을 사용하도록 (existingValue, newValue) -> existingValue)로 정의 했습니다. (코드를 보면 key 5를 갖고 있는 데이터가 두개 있습니다.)

Stream<Fruit> fruits2 = Stream.of(new Fruit("1", "banana"), new Fruit("2", "apple"),
        new Fruit("3", "mango"), new Fruit("4", "kiwi"),
        new Fruit("5", "peach"), new Fruit("6", "cherry"),
        new Fruit("5", "lemon"));
Map<String, String> map = fruits2.collect(
    Collectors.toMap(item -> item.getId(), item -> item.getName(),
            (existingValue, newValue) -> existingValue));
for (String key : map.keySet()) {
    System.out.println("key: " + key + ", value: " + map.get(key));
}

key 5의 경우 peach와 lemon이 있는데, peach가 먼저 등록되었기 때문에 peach가 map에 저장됩니다.

key: 1, value: banana
key: 2, value: apple
key: 3, value: mango
key: 4, value: kiwi
key: 5, value: peach
key: 6, value: cherry

이번에는 동일 key를 갖고 있는 데이터가 있을 때, 두개의 값을 합하여 저장하도록 정의할 수 있습니다. 3번째 param으로, 두개의 값을 더한 값을 리턴하는 함수를 정의하면 됩니다.

Stream<Fruit> fruits2 = Stream.of(new Fruit("1", "banana"), new Fruit("2", "apple"),
        new Fruit("3", "mango"), new Fruit("4", "kiwi"),
        new Fruit("5", "peach"), new Fruit("6", "cherry"),
        new Fruit("5", "lemon"));
Map<String, String> map = fruits2.collect(
        Collectors.toMap(item -> item.getId(), item -> item.getName(),
                (existingValue, newValue) -> {
                    String concat = existingValue + ", " + newValue;
                    return concat;
                }));
for (String key : map.keySet()) {
    System.out.println("key: " + key + ", value: " + map.get(key));
}

key 5의 값을 보면, 두 개의 문자열이 합쳐진 문자열이 저장되었습니다.

key: 1, value: banana
key: 2, value: apple
key: 3, value: mango
key: 4, value: kiwi
key: 5, value: peach, lemon
key: 6, value: cherry
Loading script...

Related Posts

codechachaCopyright ©2019 codechacha