1. String 타입 필드 기준 그룹화 후 BigDecimal 합계 구하기
1.1 원본 데이터와 요구사항
요구사항: 출발지와 도착지가 동일한 데이터는 합쳐서 하나로 표현하고, 나머지 두 수치 필드는 합산한다.
원본 데이터 예시:

1.2 Stream API를 이용한 리스트 처리
코드는 다음과 같다:
@Override
public Map<String, Object> countCarLine(String begin, String end) {
// 라인 통계
List<CarLineVO> carLineList = dashboardMapper.countCarLine(begin, end);
// 처리된 데이터를 저장할 리스트
List<CarLineVO> mergedCarLineList = new ArrayList<>();
// 그룹화 및 합산 처리
carLineList.parallelStream()
.collect(Collectors.groupingBy(
item -> item.getDeliverAddress() + item.getCollectAddress(),
Collectors.toList()))
.forEach((key, groupList) -> {
groupList.stream()
.reduce((a, b) -> new CarLineVO(
a.getDeliverAddress(),
a.getCollectAddress(),
a.getCollectNetWeight().add(b.getCollectNetWeight()),
a.getTotalFreightPrice().add(b.getTotalFreightPrice())))
.ifPresent(mergedCarLineList::add);
});
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("carLine", mergedCarLineList);
return resultMap;
}
1.3 처리 후 요구사항에 맞는 데이터
처리된 데이터 예시:

1.4 엔티티 클래스
CarLineVO 클래스:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CarLineVO {
private String deliverAddress;
private String collectAddress;
private BigDecimal collectNetWeight;
private BigDecimal totalFreightPrice;
}
엔티티는 Lombok 플러그인을 사용한다.
2. String 타입 필드 기준 그룹화 후 int 타입 합계 구하기
2.1 엔티티 클래스
package com.qs.modules.formMaterial.model;
import com.baomidou.mybatisplus.annotation.*;
import com.qs.db.base.model.BaseModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@TableName("form_material")
@ApiModel(value = "신청서와 자재 중간 테이블", description = "신청서와 자재 중간 테이블")
public class FormMaterial extends BaseModel {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "기본키 id")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
@ApiModelProperty(value = "신청서 id")
private String applicationFormId;
@ApiModelProperty(value = "신청 자재 id")
private String materialId;
@ApiModelProperty(value = "신청 자재 수량")
private int materialCount;
@ApiModelProperty(value = "출고된 자재 총 수량")
private int takeTotalCount;
@ApiModelProperty(value = "잔여 자재 수량")
private int remainingCount;
@ApiModelProperty(value = "자재 수령 완료 여부 (0: 미완료, 1: 완료)")
private String materialFlag;
@TableField(exist = false)
private String materialNumber;
@TableField(exist = false)
private String materialName;
@TableField(exist = false)
private String queryMaterialCount;
public static final String APPLICATION_FORM_ID = "application_form_id";
public static final String MATERIAL_COUNT = "material_count";
}
2.2 요구사항
입력 데이터는 다음과 같으며, materialId가 동일한 항목은 materialCount를 합산해야 한다.
[
{
"materialId": "1453637685838372866",
"materialCount": 15
},
{
"materialId": "1453638065183809538",
"materialCount": 21
},
{
"materialId": "1482879355628838914",
"materialCount": 8
}
]
2.3 Stream 처리
// 중복된 자재 정보를 물질 ID 기준으로 그룹화하여 수량 합산 후 하나의 항목으로 병합
// formMaterialList는 원본 리스트
List<FormMaterial> mergedList = new ArrayList<>();
formMaterialList.parallelStream()
.collect(Collectors.groupingBy(FormMaterial::getMaterialId, Collectors.toList()))
.forEach((materialId, groupList) ->
groupList.stream()
.reduce((a, b) ->
new FormMaterial()
.setMaterialId(a.getMaterialId())
.setMaterialCount(a.getMaterialCount() + b.getMaterialCount()))
.ifPresent(mergedList::add));
3. 요약
이 방식은 기존의 for 루프와 유사하게 느껴지지만, 스트림 연산 내에서도 .forEach를 사용하여 반복 처리를 수행한다는 점이 특징이다.