Collector<T, ?, List> toList();
- Stream 안의 데이터를 List 형태로 반환해주는 collector.
List<Integer> numberList = Stream.of(3, 5, -3, 3, 4, 5)
.collect(Collectors.toList());
Collector<T, ?, Set> toSet();
- Stream 안의 데이터를 Set 형태로 반환해주는 collector.
- Set이기 때문에 중복값은 사라지고 순서가 무의미해짐에 유의해야 한다.
Set<Integer> numberSet = Stream.of(3, 5, -3, 3, 4, 5)
.collect(Collectors.toSet());
<T, U, A, R> Collector<T, ?, R> mapping( Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream);
- Map과 collect를 합쳐놓은 역할을 해주는 collector. 일반적으로는 map을 한 후 collect를 해도 되지만 groupingBy 등 필요할 때가 있다.
List<Integer> numberList2 = Stream.of(3, 5, -3, 3, 4, 5)
.collect(Collectors.mapping(x -> Math.abs(x), Collectors.toList()));
Collector<T, ?, T> reducing( T identity, BinaryOperator op);
- reduce를 해주는 collector.
int sum = Stream.of(3, 5, -3, 3, 4, 5)
.collect(Collectors.reducing(0, (x, y) -> x + y));
<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
Map<Integer, String> numberMap = Stream.of(3, 5, -4, 2, 6)
.collect(Collectors.toMap(x -> x, x -> "Number is " + x));
- key 는 x -> x 가 되고, value 는 "Number is " + x 가 된다.
- x -> x 는 Function.identity() 로 대체할 수 있다.
User user1 = new User()
.setId(101)
.setName("Alice")
.setVerified(true);
User user2 = new User()
.setId(102)
.setName("Bob")
.setVerified(false);
User user3 = new User()
.setId(103)
.setName("Charlie")
.setVerified(false);
List<User> users = Arrays.asList(user1, user2, user3);
Map<Integer, User> userIdToUserMap = users.stream()
.collect(Collectors.toMap(User::getId, Function.identity()));
- 위와 같이 User 객체를 담은 리스트에서 User 의 id 를 key 로 하고 id 에 해당하는 User 를 value 로 하는 map 을 만들 수 있다.
<T, K> Collector<T, ?, Map<K, List>> groupingBy(Function<? super T, ? extends K> classifier)
- Stream 안의 데이터에 classifier를 적용했을 때 결과값이 같은 값끼리 List로 모아서 Map의 형태로 반환해주는 collector이다.
- 예를 들어, stream 에 {1, 2, 5, 7, 9, 12, 13}이 있을 때 classifier 가
x -> x % 3 이라면 반환되는 map은 {0 = [9, 12], 1 = [1, 7, 13], 2 = [2, 5]} 가 된다.
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));
<T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy( Function<? super T, ? extends K> classifier,Collector<? super T, A, D> downstream);
- 두 번째 매개변수로 downstream collector를 넘길 수 있다.
- 그 경우 List 대신 collector를 적용시킨 값으로 map의 value가 만들어진다.
- 이 때 자주 쓰이는 것이 mapping / reducing 등의 collector 이다.
List<Integer> numbers = Arrays.asList(13, 2, 101, 203, 304, 402, 305, 349, 2312, 203);
Map<Integer, Set<Integer>> unitDigitSet = numbers.stream()
.collect(Collectors.groupingBy(number -> number % 10, Collectors.toSet()));
List<Integer> numbers = Arrays.asList(13, 2, 101, 203, 304, 402, 305, 349, 2312, 203);
Map<Integer, List<String>> unitDigitStrMap = numbers.stream()
.collect(Collectors.groupingBy(number -> number % 10,
Collectors.mapping(number -> "unit digit is " + number, Collectors.toList())));
- 위와 같이 mapping 을 이용해서 숫자를 문자로 바꿔서 반환할 수 있다.
- unitDigitStrMap 가 Map 이기 때문에 unitDigitStrMap.get(key) 로 결과를 확인할 수 있다.
Order order1 = new Order()
.setId(1001L)
.setAmount(BigDecimal.valueOf(2000))
.setStatus(OrderStatus.CREATED);
Order order2 = new Order()
.setId(1002L)
.setAmount(BigDecimal.valueOf(4000))
.setStatus(OrderStatus.ERROR);
Order order3 = new Order()
.setId(1003L)
.setAmount(BigDecimal.valueOf(3000))
.setStatus(OrderStatus.ERROR);
Order order4 = new Order()
.setId(1004L)
.setAmount(BigDecimal.valueOf(7000))
.setStatus(OrderStatus.PROCESSED);
List<Order> orders = Arrays.asList(order1, order2, order3, order4);
Map<OrderStatus, BigDecimal> orderStatusToSumOfAmountMap = orders.stream()
.collect(Collectors.groupingBy(Order::getStatus, // Map<OrderStatus, List<Order>>
Collectors.mapping(Order::getAmount, // Map<OrderStatus, List<BigDecimal>>
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)))); //Map<OrderStatus, BigDecimal>
- 위의 코드는 주문 목록에서 주문 상태별 총 합개를 구하는 과정이다.
- 먼저 groupingBy 로 주문상태 : 주문록록 의 Map 으로 묶는다.
- 그 다음 mapping 을 이용해서 주문목록에서 금액만 뽑아온다.
- 마지막으로 reducing 을 이용해서 주문 목록별로 합계를 구한다.
- 결과로는 {ERROR = 7000, PROCESSED=7000, CREATE=2000} 가 된다.
Collector<T, ?, Map<Boolean, List>> partitioningBy(Predicate<? super T> predicate)
- GroupingBy와 유사하지만 Function 대신 Predicate을 받아 true와 false 두 key가 존재하는 map을 반환하는 collector 이다.
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));
for(Integer evenNumber : numberPartitions.get(true)) {
System.out.println(evenNumer + ",")
}
for(Integer oddNumber : numberPartitions.get(false)) {
System.out.println(oddNumber + ",")
}
- 위와 같이 true 인값과 false 인 값으로 Map 이 형성되고, 반복문으로 각각의 값을 확인할 수 있다.
<T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream)
- downstream collector를 넘겨 List 이외의 형태로 map의 value를 만드는 것 역시 가능하다.
Stream 은 Lazy Evaluation 이 적용되어 있는 것이다.
Collecors 가 나와서야 값을 계산한다.
REFERENCES
- 이승환님의 JAVA Stream
'Java' 카테고리의 다른 글
ENUM 활용 (0) | 2022.03.14 |
---|---|
Method Reference (0) | 2022.03.06 |
LazyEvaluation,Curry,IntStream (0) | 2022.03.06 |
Stream 응용 (0) | 2022.03.06 |
함수형 인터페이스 (0) | 2022.02.26 |