본문 바로가기

Java

[Java] 이것이 자바다 - 스트림(Stream)

스트림이란?

스트림(Stream)은 자바 8부터 추가된 문법으로 컬렉션의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자이다.

 

Stream이 추가 되기 전인 자바 7 버전까지는 List<String> 컬렉션에서 요소를 순차적으로 처리하기 위해 아래와 같이 Iterator 반복자를 사용했었다.

public class StreamTest {

    public static void main(String[] args) {
        List<String> nameList = new ArrayList<>();
        nameList.add("홍길동");
        nameList.add("스프링");
        nameList.add("스트림");
        Iterator<String> iterator = nameList.iterator();
        while (iterator.hasNext()) {
            String name = iterator.next();
            System.out.println(name);
        }
    }
	
}

하지만 자바 8 버전 부터는 Stream을 사용하여 아래와 같이 람다식으로 정리할 수 있게 되었다.

public class StreamTest2 {

	public static void main(String[] args) {
        List<String> nameList = new ArrayList<>();
        nameList.add("홍길동");
        nameList.add("스프링");
        nameList.add("스트림");
        
        // nameList 리스트에 저장된 요소인 name을 파라미터로 해서 순차적으로 출력
        nameList.stream().forEach(name -> System.out.println(name));
    }
    
}

 위 두가지 코드 모두 같은 결과를 출력한다.

중간 처리와 최종 처리

스트림은 컬렉션의 요소에 대해 중간 처리와 최종 처리를 수행할 수 있는데 중간처리에서는 매핑, 필터링, 정렬을 수행하고 최종 처리에서는 반복, 카운팅, 평균, 총합 등의 집계 처리를 수행한다.

중간 처리와 최종 처리 사용 예시

stream().map().collect(toList())

 

map()

map 메소드는 리스트에 저장된 요소를 다른 대체 요소로 구성된 새로운 스트림을 리턴해 준다.

 

collect()

collect 메소드는 중간 처리에서 필터링 또는 매핑된 요소들을 새로운 컬렉션에 수집하고, 이 컬렉션을 리턴해 준다.

 

toList()

toList는 collect 메소드의 매개값인 Collectors의 정적 메소드로 Collector의 파라미터인 T를 List에 저장한다.

 

즉 stream().map().collect(toList())는 리스트 요소들을 map()을 이용해 새로운 요소로 매핑한 뒤 collect(toList())를 이용해 매핑된 요소들을 새로운 컬렉션(리스트)에 저장한 후 리턴해 준다.

 

아래는 cartId로 찾은 제네릭타입이 CartProduct인 cartProductList를 stream().map().collect(toList())를 이용해 제네릭타입이 CartProductResponseDto인 responseDto 리스트로 매핑하여 리턴한 예시이다.

@Transactional(readOnly = true)
public List<CartProductResponseDto> getAllCartProduct(Long userId) {
    Cart cart = cartRepository.findByUserId(userId)
            .orElseThrow(() -> new ErrorCustomException(ErrorCode.NO_AUTHENTICATION_ERROR));
    List<CartProduct> cartProductList = cartProductRepository.findAllByCartId(cart.getId());
    List<CartProductResponseDto> responseDto = cartProductList
            .stream()
            .map(o -> new CartProductResponseDto(o))
            .collect(toList());
    return responseDto;
}
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
public class CartProduct {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cart_product_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="cart_id")
    private Cart cart;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id")
    private Product product;

    @Column(nullable = false)
    private int productCount;

    @Builder
    public CartProduct(final Cart cart, final Product product, final int productCount) {
        this.cart = cart;
        this.product = product;
        this.productCount = productCount;
    }

    public void updateCartProduct(UpdateCartDto requestDto) {
        this.productCount = requestDto.getProductCount();
    };

}
@Getter
@NoArgsConstructor
public class CartProductResponseDto {
    private Long cartProductId;
    private Long productId;
    private String productName;
    private String productInfo;
    private int productPrice;
    private int productCount;

    @Builder
    public CartProductResponseDto(final CartProduct cartProduct) {
        this.cartProductId = cartProduct.getId();
        this.productId = cartProduct.getProduct().getId();
        this.productName = cartProduct.getProduct().getProductName();
        this.productInfo = cartProduct.getProduct().getProductInfo();
        this.productPrice = cartProduct.getProduct().getProductPrice();
        this.productCount = cartProduct.getProductCount();
    }

}