본문 바로가기

Language/Java

Java 스트림 (Stream) 사용법 및 정리 3/3 (Collectors, Grouping By ..)

반응형

목차

· Collectors

· toMap

· Grouping By

· Partitioning By

· For Each


Collectors


<R, A> R collect(Collector<? super T, A, R> collector);

java.util.stream.Collectors
Collector<T, ?, List<T>> toList();
Collector<T, ?, Set<T>> toSet();

collect – 주어진 collector를 이용해 Stream안의 데이터를 합침. 일반적으로 특정 data structure로 데이터를 모을 때 사용한다. Collectors – 자주 쓰일법한 유용한 collector들을 모아놓은 util class. java.util.stream 패키지에서 제공한다.

toList – Stream 안의 데이터를 List 형태로 반환해주는 collector이다.

toSet – Stream 안의 데이터를 Set 형태로 반환해주는 collector이다.

 

다음은 List와 Set으로 스트림 데이터를 합치는 과정이다.

List<Integer> numberList = Stream.of(3, 5, -3, 3, 4, 5)
        .collect(Collectors.toList());
System.out.println("numberList = " + numberList);

Set<Integer> numberSet = Stream.of(3, 5, -4, 4, 4, 5)
        .collect(Collectors.toSet());
System.out.println("numberSet = " + numberSet);

collect로 데이터를 합칠 때  Collectors의 mapping과 reducing을 적용할 수 있다.

List<Integer> integerList = Stream.of(3, 5, -3, 3, 4, 5)
        .collect(Collectors.mapping(x -> Math.abs(x), Collectors.toList()));
Set<Integer> integerSet = Stream.of(3, 5, -3, 3, 4, 5)
        .collect(Collectors.mapping(x -> Math.abs(x), Collectors.toSet()));
System.out.println("integerList = " + integerList);
System.out.println("integerSet = " + integerSet);

Integer sum = Stream.of(3, 5, -3, 3, 4, 5)
        .collect(Collectors.reducing(0, (x, y) -> x + y));
System.out.println("sum = " + sum);

 

public static <T, U, A, R> Collector<T, ?, R> mapping(
	Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream)

public static <T> Collector<T, ?, T> reducing(
	T identity, BinaryOperator<T> op)

mapping – Map과 collect를 합쳐놓은 역할을 해주는 collector

reducing – reduce를 해주는 collector

 

toMap


public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
    Function<? super T, ? extends K> keyMapper,
    Function<? super T, ? extends U> valueMapper)

Stream 안의 데이터를 map의 형태로 반환해주는 collector

keyMapper – 데이터를 map의 key로 변환하는 Function

valueMapper – 데이터를 map의 value로 변환하는 Function

 

다음은 toMap을 사용해 멤버 아이디를 Key로 Member를 값으로 하는 Map을 만든다.

List<Member> members = new ArrayList<>();
members.add(new Member(1, "Kim", 20));
members.add(new Member(2, "An", 40));
members.add(new Member(3, "Oh", 60));

Map<Integer, Member> memberIdMap = members.stream()
        .collect(Collectors.toMap(Member::getId, Function.identity()));

 

Grouping By


public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(
	Function<? super T, ? extends K> classifier)

Stream 안의 데이터에 classifier를 적용했을 때 결괏값이 같은 값끼리 List로 모아서 Map의 형태로 반환해주는 collector.

이 때 key는 classifier의 결괏값, value는 그 결괏값을 갖는 데이터들.

 

처음 예시는 10으로 나눴을 때 나머지를 key로 하고 이에 해당하는 스트림 데이터 리스트를 value로 가지는 Map을 만든다.

두 번째 예시는 처음 예시의 value인 리스트를 Set으로 바꿔준다.

세 번째 예시는 처음 예시의 value인 리스트에 mapping을 적용한 이후 리스트로 변형한다.

List<Integer> numbers = Arrays.asList(13, 2, 101, 203, 304, 402, 305, 349, 2312, 203);
Map<Integer, List<Integer>> unitDigitMap = numbers.stream()
        .collect(Collectors.groupingBy(number -> number % 10));
System.out.println("unitDigitMap = " + unitDigitMap);

// unitDigitMap = {1=[101], 2=[2, 402, 2312], 3=[13, 203, 203], 4=[304], 5=[305], 9=[349]}

Map<Integer, Set<Integer>> unitDigitSet = numbers.stream()
        .collect(Collectors.groupingBy(number -> number % 10, Collectors.toSet()));
System.out.println("unitDigitSet = " + unitDigitSet);

// unitDigitSet = {1=[101], 2=[2, 402, 2312], 3=[203, 13], 4=[304], 5=[305], 9=[349]}

Map<Integer, List<String>> unitDigitStrMap = numbers.stream()
        .collect(Collectors.groupingBy(number -> number % 10,
                Collectors.mapping(number -> "unit digit is " + number, Collectors.toList())));
                
// unitDigitStrMap = {1=[unit digit is 101], 2=[unit digit is 2, unit digit is 402, unit digit is 2312], 3=[unit digit is 13, unit digit is 203, unit digit is 203], 4=[unit digit is 304], 5=[unit digit is 305], 9=[unit digit is 349]}

 

Partitioning By


public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(
	Predicate<? super T> predicate)
public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(
	Predicate<? super T> predicate, Collector<? super T, A, D> downstream

GroupingBy와 유사하지만 Function 대신 Predicate을 받아 true와 false 두 key가 존재하는 map을 반환하는 collector

마찬가지로 downstream collector를 넘겨 List 이외의 형태로 map의 value를 만드는 것 역시 가능

 

List<Integer> numbers = Arrays.asList(13, 2, 101, 203, 304, 402, 305, 349, 2312, 203);
// 짝수인 그룹, 홀수인 그룹으로 나누기
Map<Boolean, List<Integer>> numberPartitions = numbers.stream()
    .collect(Collectors.partitioningBy(number->number %2 ==0 ));
System.out.println("numberPartitions.get(true) = " + numberPartitions.get(true));
System.out.println("numberPartitions.get(false) = " + numberPartitions.get(false));

// numberPartitions.get(true) = [2, 304, 402, 2312]
// numberPartitions.get(false) = [13, 101, 203, 305, 349, 203]

 

For Each


void forEach(Consumer<? super T> action);

제공된 action을 Stream의 각 데이터에 적용해주는 종결 처리 메서드

Java의 iterable 인터페이스에도 forEach가 있기 때문에 Stream의 중간 처리가 필요 없다면 iterable collection(Set, List 등)에서 바로 쓰는 것도 가능

 

List<Integer> numbers = Arrays.asList(3, 5, 2, 1);
numbers.stream().forEach(number-> System.out.println("number = " + number));

 

반응형