티스토리 뷰

● 도입

- 이전 글에서는 모두 Stream 안에 원하는 데이터들이 바로 들어있었다.

- 그렇기에 map, filter 등의 method들을 바로 적용할 수 있었다.

- 그러나 Stream을 사용하다 보면 그 안에 있는 데이터에 여러가지 처리를 거쳐도 여전히 안에 Stream이 들어있는 경우가 있다.(Stream 안에 Stream이 들어있는 형태)

- map을 이용해 데이터를 변형할 때 그 결과물이 Stream이 된다면 그 Stream 들을 쭉 이어서 하나의 Stream으로 만들어주는 것이 바로 flatMap method이다.

- Map + Flatten
- 데이터에 함수를 적용한 후 중첩된 stream을 연결하여 하나의 stream으로 return
======================================================================================
[데이터에 함수를 적용한 후 중첩된 stream을 연결하여 하나의 stream으로 return]
(위의 말을 굳이 순서를 나누자면 아래와 같다.)
1. 데이터에 함수를 적용한 후  →  map을 적용
2. 중첩된 stream을 연결하여 하나의 stream으로  →  flat(납작하게)
[Stream interface에 있는 flatMap method]

public interface Stream<T> extends BaseStream<T, Stream<T>> {
	<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);	
}

- T type 데이터를 받아서 'R type의 데이터가 들어있는 Stream을 반환'한다.(return type이 Stream이다.)
- R type의 Stream'들'이 담겨있는 Stream을 받은 후 이 각각의 Stream들을 납작하게 쭉 이어서
최종적으로는 'R type의 Stream들'이 아니라 'R type의 data'를 받을 수 있는 Stream을 만드는 것이다.
(Stream을 납작하게 = Stream을 벗기는 것이다.)
[Stream interface에 있는 map method]

public interface Stream<T> extends BaseStream<T, Stream<T>> {
	<R> Stream<R> map(Function<? super T, ? extends R> mapper);
}

- T type 데이터를 받아서 해당 데이터를 변형한 후 R type 데이터로 return한다.

출처 - 네이버 사전

 

 

● 실습

- 실습전에 조금 헷갈리는 내용을 정리했다.

[Collection의 stream() method]
- java의 Collection 객체들은 stream() method를 사용할 수 있다.
- Collection 객체에 stream() method를 사용하면 Stream 객체를 만들 수 있다.

[Arrays의 stream() method]
- Arrays.stream()의 인자로 배열을 넣어주면 배열을 Stream 객체로 만들 수 있다.

출처 - https://hbase.tistory.com/171

1.

package com.fastcampus.functionalprogramming.chapter6;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Chapter6Section7 {
	public static void main(String[] args) {
		// 1.
		// 목표 : 이차원 배열 cities를 도시들을 담고있는 List로 만들어보자
		String[][] cities = new String[][] {
			{ "Seoul", "Busan" },
			{ "San Francisco", "New York" },
			{ "Madrid", "Barcelona" }
		};
		
		// 1-1. map method를 이용해보자
		Stream<String[]> cityStream = Arrays.stream(cities); // Arrays.stream() method를 이용하면 배열을 Stream으로 만들 수 있다.
		/*
		 * 현재 cityStream에는 아래와 같은 형태로 데이터가 들어있다.(String[]가 하나씩 들어있다.)
		 * { "Seoul", "Busan" }				--> 한 덩어리(String[] 형태로 들어있다.)
		 * { "San Francisco", "New York" } 	--> 한 덩어리(String[] 형태로 들어있다.)
		 * { "Madrid", "Barcelona" }		--> 한 덩어리(String[] 형태로 들어있다.)
		 */
		
		Stream<Stream<String>> cityStreamStream = cityStream.map(x -> Arrays.stream(x));
		/*
		 * 현재 cityStreamStream에는 아래와 같은 형태로 데이터가 들어있다.
		 * { "Seoul", "Busan" }				--> 이 한 덩어리가 Stream<String>이 되었다.
		 * { "San Francisco", "New York" } 	--> 이 한 덩어리가 Stream<String>이 되었다.
		 * { "Madrid", "Barcelona" }		--> 이 한 덩어리가 Stream<String>이 되었다.
		 * 
		 * Arrays.stream() method는 Stream을 return 하기 때문이다.
		 */
		
		// cityStreamStream을 List로 만들어보자
		List<Stream<String>> cityStreamList = cityStreamStream.collect(Collectors.toList());
		/*
		 * 현재 cityStreamList에는 아래와 같은 형태로 데이터가 들어있다.
		 * { "Seoul", "Busan" }				--> cityStreamList의 0번 index(Stream<String> 형태로 들어있다.)
		 * { "San Francisco", "New York" } 	--> cityStreamList의 1번 index(Stream<String> 형태로 들어있다.)
		 * { "Madrid", "Barcelona" }		--> cityStreamList의 2번 index(Stream<String> 형태로 들어있다.)
		 */
		System.out.println("cityStreamList : " + cityStreamList);
		/*
		 * - 결과적으로 List인데 그 안에 Stream<String>이 들어있는 이상한 List가 만들어졌다. --> List<Stream<String>>
		 * - cityStreamList 안에는 Stream이 들어있기 때문에 원하는 값을 출력할 수도 없다.
		 * - 나는 "Seoul", "Barcelona" 같은 도시 이름이 각각 하나씩 들어있는 List를 원한다.
		 * - 이때 바로 map method 대신 flatMap method를 사용하는 것이다.
		 */
// =============================================		
		// 1-2. flatMap
		Stream<String[]> cityStream2 = Arrays.stream(cities);
		Stream<String> flattenedCityStream = cityStream2.flatMap(x -> Arrays.stream(x));
		/*
		 * - (x -> Arrays.stream(x))을 통해 아래와 같이 된 것은 map method를 이용한 것과 동일하다.
		 *  
		 * { "Seoul", "Busan" }				--> 이 한 덩어리가 Stream<String>이 되었다.
		 * { "San Francisco", "New York" } 	--> 이 한 덩어리가 Stream<String>이 되었다.
		 * { "Madrid", "Barcelona" }		--> 이 한 덩어리가 Stream<String>이 되었다.
		 * 
		 * - 하지만 flatMap method로 인해 Stream<String>의 Stream이 모두 벗겨져 그 안에 있는 String들이 하나로 쭉 이어져서 납작하게 됐다.
		 * - 그렇기에 Stream<Stream<String>> 같은 형태가 아니라 Stream<String> 형태가 되었다.
		 */
		List<String> flattenedCityList = flattenedCityStream.collect(Collectors.toList());
		System.out.println("flattenedCityList : " + flattenedCityList);
	}
}

 

2.

package com.fastcampus.functionalprogramming.chapter6.model;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

public class Order {
	private long id;
	private LocalDateTime createdAt;
	private long createdByUserId;
	private OrderStatus status;
	private BigDecimal amount;
	private List<OrderLine> orderLines;

	public enum OrderStatus {
		CREATED,
		IN_PROGRESS,
		ERROR,
		PROCESSED
	}

	public long getId() {
		return id;
	}

	public Order setId(long id) {
		this.id = id;
		return this;
	}

	public LocalDateTime getCreatedAt() {
		return createdAt;
	}

	public Order setCreatedAt(LocalDateTime createdAt) {
		this.createdAt = createdAt;
		return this;
	}

	public long getCreatedByUserId() {
		return createdByUserId;
	}

	public Order setCreatedByUserId(long createdByUserId) {
		this.createdByUserId = createdByUserId;
		return this;
	}

	public OrderStatus getStatus() {
		return status;
	}

	public Order setStatus(OrderStatus status) {
		this.status = status;
		return this;
	}

	public BigDecimal getAmount() {
		return amount;
	}

	public Order setAmount(BigDecimal amount) {
		this.amount = amount;
		return this;
	}

	public List<OrderLine> getOrderLines() {
		return orderLines;
	}

	public Order setOrderLines(List<OrderLine> orderLines) {
		this.orderLines = orderLines;
		return this;
	}

	@Override
	public String toString() {
		return "Order [id=" + id + ", " + (createdAt != null ? "createdAt=" + createdAt + ", " : "")
				+ "createdByUserId=" + createdByUserId + ", " + (status != null ? "status=" + status + ", " : "")
				+ (amount != null ? "amount=" + amount + ", " : "")
				+ (orderLines != null ? "orderLines=" + orderLines : "") + "]";
	}
}
package com.fastcampus.functionalprogramming.chapter6.model;

import java.math.BigDecimal;

public class OrderLine {
	private long id;
	private OrderLineType type;
	private long productId;
	private int quantity;
	private BigDecimal amount;
	
	public enum OrderLineType {
		PURCHASE,
		DISCOUNT
	}

	public long getId() {
		return id;
	}

	public OrderLine setId(long id) {
		this.id = id;
		return this;
	}
	
	public OrderLineType getType() {
		return type;
	}
	
	public OrderLine setType(OrderLineType type) {
		this.type = type;
		return this;
	}

	public long getProductId() {
		return productId;
	}

	public OrderLine setProductId(long productId) {
		this.productId = productId;
		return this;
	}
	
	public int getQuantity() {
		return quantity;
	}
	
	public OrderLine setQuantity(int quantity) {
		this.quantity = quantity;
		return this;
	}

	public BigDecimal getAmount() {
		return amount;
	}

	public OrderLine setAmount(BigDecimal amount) {
		this.amount = amount;
		return this;
	}

	@Override
	public String toString() {
		return "OrderLine [id=" + id + ", " + (type != null ? "type=" + type + ", " : "") + "productId=" + productId
				+ ", quantity=" + quantity + ", " + (amount != null ? "amount=" + amount : "") + "]";
	}
}
package com.fastcampus.functionalprogramming.chapter6;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.fastcampus.functionalprogramming.chapter6.model.Order;
import com.fastcampus.functionalprogramming.chapter6.model.OrderLine;
import com.fastcampus.functionalprogramming.chapter6.model.OrderLine.OrderLineType;

public class Chapter6Section7 {
	public static void main(String[] args) {
		Order order1 = new Order()
				.setId(1001)
				.setOrderLines(Arrays.asList(
						new OrderLine()
							.setId(10001)
							.setType(OrderLineType.PURCHASE)
							.setAmount(BigDecimal.valueOf(5000)),
						new OrderLine()
							.setId(10002)
							.setType(OrderLineType.PURCHASE)
							.setAmount(BigDecimal.valueOf(4000))
				));
		Order order2 = new Order()
				.setId(1002)
				.setOrderLines(Arrays.asList(
						new OrderLine()
							.setId(10003)
							.setType(OrderLineType.PURCHASE)
							.setAmount(BigDecimal.valueOf(2000)),
						new OrderLine()
							.setId(10004)
							.setType(OrderLineType.DISCOUNT)
							.setAmount(BigDecimal.valueOf(-1000))
				));
		Order order3 = new Order()
				.setId(1003)
				.setOrderLines(Arrays.asList(
						new OrderLine()
							.setId(10005)
							.setType(OrderLineType.PURCHASE)
							.setAmount(BigDecimal.valueOf(2000))
				));
		// order1, order2, order3 각각의 orderLine List 속 OrderLine 들을 하나로 합쳐서 하나의 List<OrderLine>로 만들어보자
		
		// 1. 내 방법
		List<Order> orders = Arrays.asList(order1, order2, order3);
		Stream<Order> orderStream = orders.stream();
		Stream<OrderLine> orderLineStream = orderStream.flatMap(order -> order.getOrderLines().stream());
		List<OrderLine> orderList = orderLineStream.collect(Collectors.toList());
		System.out.println(orderList);
		
		// 2. 강의
		List<Order> orders2 = Arrays.asList(order1, order2, order3);
		List<OrderLine> orderList2 = orders2.stream()					// Stream<Order>
									.map(Order::getOrderLines)			// Stream<List<OrderLine>>
									.flatMap(order -> order.stream())	// Stream<OrderLine>	
																		// stream() : Collection을 Stream으로 바꿔주는 method(SET, LIST 모두 사용 가능)
																		// 여기서 그냥 map을 써버리면 --> .map(List::stream) --> Stream<Stream<OrderLine>>이 된다.
																		// 따라서 Stream을 벗겨주는 flatMap을 사용해야 한다. 
									.collect(Collectors.toList());
		System.out.println(orderList2);
	}
}

1번과 2번 방법 모두 결과값 동일

[
OrderLine [id=10001, type=PURCHASE, productId=0, quantity=0, amount=5000],
OrderLine [id=10002, type=PURCHASE, productId=0, quantity=0, amount=4000],
OrderLine [id=10003, type=PURCHASE, productId=0, quantity=0, amount=2000],
OrderLine [id=10004, type=DISCOUNT, productId=0, quantity=0, amount=-1000],
OrderLine [id=10005, type=PURCHASE, productId=0, quantity=0, amount=2000]
]
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함