Engineering Note

[Java] Stream API 실전 예제(Entity/DTO 변환 과정: forEach -> map 리팩토링) 본문

Programming Language/Java

[Java] Stream API 실전 예제(Entity/DTO 변환 과정: forEach -> map 리팩토링)

Software Engineer Kim 2025. 10. 4. 22:44

Entity와 DTO 변환 과정을 for문 대신 Stream으로 변환하면서 알게된 내용을 정리하려고 한다.

 

 

1. 초기 forEach를 사용한 비효율적인 방식 코드

public List<OrderDto> converWithForEach(List<Order> orderEntities) {

 List<OrderDto> orderDtos = new ArrayList<>();
 
 orderEntities.stream().forEach(order ->{
 OrderDto dto = OrderDto.from(order);
 orderDtos.add(dto);
 });
 
 return orderDtos;
}

 

forEach 방식의 문제점

함수형 프로그래밍 위반

: 스트림 파이프라인 외부에서 선언된 orderDtos라는 변이 가능한 상태를 스트림 내부에서 변경해야 하는데 이는 함수형 프로그래밍 원칙에 위반됩니다.(병렬 스트림 처리시 스레드 안전성 문제를 야기할 수 있습니다.)

: 가독성 측면에서도 new ArrayList<>() 선언과 forEach 내부 로직 때문에 코드가 불필요하게 늘어납니다.

 

2. 리팩토링:map과 collect를 사용한 모범 사례

map을 사용하여 Entity를 DTO로 변환하고, collect를 사용하여 변환된 결과를 새로운 리스트로 안전하게 수집합니다.

public List<OrderDto> convertWithStreamMap(List<Order> orderEntities){
	List<OrderDto> orderDtos = orderEntities.stream().map(OrderDto::from).collect(Collectors.toList());

	return orderDtos;
}

 

 

 

3. 사용된 디자인 패턴 :정적 팩터리 메서드(OrderDto.from)

이 방식의 효율성은 DTO 클래스 내에 변환 로직을 캡슐화한 정적 팩터리 메서드가 있기에 가능합니다.

@Getter
@Setter
@AllArgsConstructors
public class OrderDto{

    private Long id;
    private String orderNumber;
    private List<OrderItemDto> items;
    
    //정적 팩터리 메서드: Entity를 받아 DTO 생성, 반환
    public static OrderDto from(Order order){
    	//중적 리스트 속성은 내부에서 다시 stream map을 통해 재귀적 변환
    	List<OrderItemDto> itemDtos = ordergetItems().stream().map(OrderItemDto::from).collect(Collectors.toList());
        
        return new OrderDto(order.getId(), order.getOrderNumber(), itemDtos);
    }
    
}

 

 

4. 핵심 동작 원리: map 함수의 역할

map 함수는 stream 파이프라인에서 중간 연산을 담당하는 가장 중요한 메서드입니다.

 

Map 함수의 정의

map 함수는 이 스트림의 각 요소에 주어진 함수(mapper)를 적용한 결과로 구성된 새로운 스트림을 반환 합니다.

요소 동작 설명
입력 스트림 Stream<Order> (Entity 타입의 요소들)
주어진 함수 (Mapper) OrderDto::from (Orer Entity를 OrderDto로 변환하는 정적 팩터리 메서드)
변환 map은 스트림의 각 Order 요소에 OrderDto::from을 적용합니다. 이 함수의 반환 값은 새로운 OrderDto 객체입니다.
출력 스트림 Stream<OrderDto> (새로운 DTO 타입의 요소들로 구성된 스트림)

 

 

ModelMapper 라이브러리를 사용하면 DTO와 Entity 간 변환을 편리하게 할 수 있지만, 이번 리팩토링을 통해 정적 팩토리 메서드를 통해 코드의 가독성을 높이는 방식과 stream map 함수의 사용 방식에 대해 자세히 알게 되었다.

Comments