Java/모던자바인액션요약

스트림으로 데이터 수집

Junuuu 2022. 8. 23. 00:01
반응형

개요

만약 통화별로 트랜잭션을 그룹화하기 위해서 코드를 작성하려면 어떻게 해야 할까요?

Map<Currency, List<Transaction>> transactionByCurrencies = new HashMap<>();

//트렌젝션 리스트에서 하나씩 꺼내옴
for(Transaction transaction : transactions){
	Currency currency = transaction.getCurretncy();
	List<Transaction> transactionForCurrency = transactionByCurrencies.get(currency);
	if(transactionForCurrency == null){
		transactionForCurrency = new ArrayList<>();
		transactionByCurrencies.put(currency, transactionForCurrency);
	}
	transactionForCurrency.add(transaction);
}

'통화별로 트랜잭션 리스트를 그룹화하시오' 라고 간단히 표현할 수 있지만 코드가 무엇을 실행하는지 한눈에 파악하기 힘듭니다.

 

Stream에 toList를 사용하는 대신 더 범용적인 컬렉션 파라미터를 collect 메서드에 전달함으로써 원하는 연산을 훨씬 간결하게 구할 수 있습니다.

Map<Currency, List<Transaction>> transactionByCurrencies = 
transactions.stream().collect(groupingBy(Transaction::getCurrency));

 

훨씬 간단해진 모습을 볼 수 있습니다.

 

컬렉터란 무엇인가?

이전 예제에서 collect 메서드로 Collector 인터페이스 구현체를 전달했습니다.

'각 요소를 리스트로 만들어라'를 의미하는 toList를 사용했습니다.

 

컬렉터는 리듀싱 연산을 이용해서 스트림의 각 요소를 방문하며 컬렉터가 작업을 처리합니다.

 

위의 예시인 groupingBy 같은 컬렉터 인터페이스 구현체를 사용하면 각 트렌젝션에서 통화를 추출한 다음에 통화를 키로 사용해서 트랜젝션 자체를 결과 맵에 누적시킵니다.

 

보통 구현되어 있는 컬렉터들은 크게 세 가지로 구분할 수 있습니다.

- 스트림 요소를 하나의 값으로 리듀스 하고 요약

- 요소 그룹화

- 요소 분할

 

제공되는 컬렉터들 기능 요약

counting()

개수를 측정

 

maxBy(), minBy()

인자로 Comparator가 들어가며 최대/최소 값을 계산할 수 있습니다.

 

summingInt()

인자로 객체를 int로 매핑하는 함수를 받아 값의 합을 계산할 수 있습니다.

유사한 메서드로 summingDouble, summingLong이 있습니다.

 

이외에도 averagingInt, averagingDouble, averagingLong, summarzingInt 등의 메서드들이 있습니다.

 

joining()

인자를 넣어서 두 요소 사이에 구분 문자열을 넣을 수도 있습니다.

내부적으로 StringBuilder를 이용해서 문자열을 하나로 만들어줍니다.

 

reducing()

위의 모든 켈렉터들은 reducing 팩토리 메서드로 구현할 수 있습니다.

그럼에도 위의 컬렉터들을 소개한 이유는 프로그래밍적으로 편의성, 가독성이 증가하기 때문입니다.

 

groupingBy()

인자로 분류함수를 넣어주어야 합니다.

쉽게 그룹핑 할 수 있습니다.

각 키에 대응하는 스트림의 모든 항목을 리스트를 값으로 갖는 맵이 반환됩니다.

 

partitioningBy()

인자로 Boolean을 반환하는 분할 함수를 넣어주어야 합니다.

쉽게 분할할 수 있습니다.

최대 두 개의 그룹으로 분류됩니다(참 or 거짓)

 

 

Collector 인터페이스 직접 구현하기

public interface Collector<T, A, R>{
	Supplier<A> supplier();
	BiConsumer<A, T> accumulator();
	Function<A, R> finisher();
	BinaryOperator<A> combiner();
	Set<Characteristics> characteristics();
}

 

다섯 가지 메서드를 직접 구현하여 자신만의 커스텀 컬렉터를 만들 수 있습니다.

 

직접 커스텀한 컬렉터를 구현할 수 있으며 이를 통해 성능 향상도 노려볼 수 있습니다.

 

개인적으로 아직 잘 와닿지 않는 부분이라 디테일하게 읽고 정리하진 않았습니다.