기억해놓으면 자주 사용할 것 같은 Stream API 의 메서드들이 있어서 자주 보면서 기억하고자 포스팅 하는 글
아래와 같은 Id, Amount, Status를 필드로 가지는 Order객체를 이리저리 다루며 테스트코드를 작성해보았다.
public class GroupingBy {
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);
ToMap
ToMap 메서드는 Collectors 클래스의 메서드인데, 파라미터로 Function 인터페이스를 전달받는다.
즉, 객체의 특성 속성을 Key로 하고, 특정 속성이나 혹은 객체 그 자체를 Value로 갖는 Map을 리턴한다.
@Test
void toMapPractice() {
//TODO : orderID를 Key로 갖고, Status를 Value로 갖는 Map으로 바꾸기
Map<Long, OrderStatus> orderStatusMap = orders.stream()
.collect(Collectors.toMap(Order::getId, Order::getStatus));
Assertions.assertEquals(orderStatusMap.get(1001L), OrderStatus.CREATED);
}
위와 같이 Id를 Key로 갖고, Status를 Value로 갖는 Map이 만들어진다.
DB에서 SELECT 한 엔티티를 Id를 Key로 갖고, Value로 객체 그 자체를 가지는 Map을 만들어놓으면 Cache처럼 사용할 수 있다. Map은 검색에 상당한 이점을 갖는 자료구조이기 때문이다.
Grouping By
SQL에서 Group By 처럼 객체의 특정 속성을 기준으로 그룹화해서 Map을 반환하는 메서드이다.
@Test
void groupingByPractice(){
List<Order> orders = Arrays.asList(order1, order2, order3, order4);
Map<OrderStatus, List<Order>> orderStatusListMap = orders.stream()
.collect(groupingBy(x -> x.getStatus()));
System.out.println(orderStatusListMap);
//OrderStatus가 ERROR인 List는 order2, order3으로 총 2개이다.
Assertions.assertEquals(orderStatusListMap.get(OrderStatus.ERROR).size(), 2);
}
groupingBy(x -> x.getStatus) 즉, status를 기준으로 그룹화를 수행했다.
이처럼 Status가 Key, 객체 자체가 Value인 Map의 형태로 반환되었다.
@Test
void groupingByPractice2(){
List<Order> orders = Arrays.asList(order1, order2, order3, order4);
Map<OrderStatus, BigDecimal> addResultMap = orders.stream()
.collect(groupingBy(x -> x.getStatus(),
Collectors.mapping(x -> x.getAmount(),
reducing(BigDecimal.ZERO, BigDecimal::add))));
System.out.println(addResultMap);
}
위 메서드는 각 Status 별로 Amount의 총합을 구하는 메서드이다.
mapping 메서드를 통해서 특정 속성에 대해서 reducing을 수행할 수 있다.
Partition By
@Test
void partitionByPractice(){
Map<Boolean, List<Order>> nonErrorStatusListMap = orders.stream().collect(
Collectors.partitioningBy(order -> !order.getStatus().equals(OrderStatus.ERROR)));
// partitioningBy는 파라미터로 Predicate을 넘겨서, 조건 만족 여부에 따른 boolean을 key값으로 하는 Map을 리턴
// status가 ERROR인 주문의 개수는 1개이므로 true를 key로 가지는 map의 value는 1개뿐
Assertions.assertEquals(nonErrorStatusListMap.get(true).size(),1);
Assertions.assertEquals(nonErrorStatusListMap.get(false).size(),3);
}
Partition By는 파라미터로 Predicate를 전달받는다. Predicate는 boolean을 반환하는 즉, 조건에 부합하는지를 반환한다.
위처럼 order.getStatus()가 ERROR인지 판별하여 반환하는 경우에 Pridecate의 조건을 만족하는 객체들은 true인 Key값의 Value로 할당되고, 조건을 만족하지 못하는 객체는 false인 Key값의 Value로 할당받게 된다.
Map.get(true)로 Value를 꺼내보면 조건을 만족하는 객체들을 분류할 수 있게 된다.
'모던 자바 인 액션' 카테고리의 다른 글
[모던 자바 인 액션] 함수형 인터페이스에 람다식 전달하기 (0) | 2024.03.03 |
---|---|
[모던 자바 인 액션] 2. '동작 파라미터화'란? (0) | 2024.02.16 |
[모던 자바 인 액션] 1. 자바의 발전 과정에 대하여 (1) | 2024.02.16 |
[모던 자바 인 액션] 자바 8이 궁극적으로 추구하는 것. (0) | 2023.09.13 |