๐Ÿ“Œ๋ชจ๋˜ ์ž๋ฐ” ์ธ ์•ก์…˜ Chapter 5. ์ŠคํŠธ๋ฆผ ํ™œ์šฉ

๋ชจ๊น…ยท2023๋…„ 12์›” 14์ผ
0

๐Ÿ“– 5.1 ํ•„ํ„ฐ๋ง

ํ”„๋ ˆ๋””์ผ€์ดํŠธ ํ•„ํ„ฐ๋ง ๋ฐฉ๋ฒ•๊ณผ๊ณ ์œ  ์š”์†Œ๋งŒ ํ•„ํ„ฐ๋งํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šด๋‹ค.

5.1.1 ํ”„๋ฆฌ๋””์ผ€์ดํŠธ๋กœ ํ•„ํ„ฐ๋ง

filter ๋ฉ”์„œ๋“œ๋Š” ํ”„๋ ˆ๋””์ผ€์ดํŠธ(๋ถˆ๋ฆฌ์–ธ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜)๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์•„์„œ ํ”„๋ ˆ๋””์ผ€์ดํŠธ์™€ ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  ์š”์†Œ๋ฅผ ํฌํ•จํ•˜๋Š” ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

// ์ฑ„์‹์š”๋ฆฌ๋ฅผ ํ•„ํ„ฐ๋งํ•ด์„œ ๋ฉ”๋‰ด ๋งŒ๋“ค๊ธฐ
List<Dish> vegetarianMenu = menu.stream()
								.filter(Dish::lsVegetarian)
								.collect(toList())๏ผ›

5.1.2 ๊ณ ์œ  ์š”์†Œ ํ•„ํ„ฐ๋ง

// ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ์ง์ˆ˜๋ฅผ ์„ ํƒํ•˜๊ณ  ์ค‘๋ณต์„ ํ•„ํ„ฐ๋ง
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); 
numbers.stream()
	   .filter(i -> i % 2 == 0)
	   .distinct()
	   .forEach(System.out::println);

๐Ÿ“– 5.2 ์ŠคํŠธ๋ฆผ ์Šฌ๋ผ์ด์‹ฑ

์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋ฅผ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ์Šคํ‚ตํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•œ๋‹ค.

5.2.1 ํ”„๋ ˆ๋””์ผ€์ดํŠธ๋ฅผ ์ด์šฉํ•œ ์Šฌ๋ผ์ด์‹ฑ

TAKEWHILE ํ™œ์šฉ

๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน๋ณ„ํ•œ ์š”๋ฆฌ ๋ชฉ๋ก์„ ๊ฐ–๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

List<Dish> specialMenu = A rrays.asList(
	new Dish("seasonal fruit", true, 120, Dish.Type.OTHER), 
	new Dish("prawns", false, 300, Dish.Type.FISH), 
	new Dish("rice", true, 350, Dish.Type.OTHER), 
	new Dish("chicken", false, 400, Dish.Type.MEAT), 
	new Dish("french fries", true, 530, Dish.Type.OTHER));

์–ด๋–ป๊ฒŒ 320์นผ๋กœ๋ฆฌ ์ดํ•˜์˜ ์š”๋ฆฌ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์„๊นŒ?
๋ณธ๋Šฅ์ ์œผ๋กœ ์•ž์—์„œ ๋ฐฐ์šด filter๋ฅผ ๋‹ค์Œ์ฒ˜๋Ÿผ ์ด์šฉํ• ์ˆ˜ ์žˆ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค ๊ฒƒ์ด๋‹ค.

List<Dish> filteredMenu 
	= specialMenu.stream()
			 	 .filter(dish -> dish.getCalories() < 320)
			 	 .collect(toList()); 

๋ฆฌ์ŠคํŠธ๊ฐ€ ์ด๋ฏธ ์นผ๋กœ๋ฆฌ ์ˆœ์œผ๋กœ ์ •๋ ฌ๋˜์—‰ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์— ์ฃผ๋ชฉํ•˜์ž.
filter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ์š”์†Œ์— ์ ์šฉํ•  ๊ฒƒ์ด๋‹ค.
์ •๋ ฌ๋˜์–ด ์žˆ๋‹ค๋ฉด 320์นผ๋กœ๋ฆฌ ๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€ ์š”๋ฆฌ๊ฐ€ ๋‚˜์™”์„ ๋•Œ ๋ฐ˜๋ณต์„ ๋ฉˆ์ถ”๋Š” ๊ฒƒ์ด ํšจ์œจ์ ์ด๋‹ค.
takeWhile์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋ฅผ ๊ฐ„๋‹จํžˆ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

List<Dish> slicedMenul 
	= specialMenu.stream()
				 .takeWhile(dish -> dish.getCalories() < 320)
				 .collect(toList()); 

DROPWHILE ํ™œ์šฉ

320์นผ๋กœ๋ฆฌ๋ณด๋‹ค ํฐ ์š”์†Œ๋Š” ์–ด๋–ป๊ฒŒ ํƒ์ƒ‰ํ• ๊นŒ?
dropWhile์„ ์ด์šฉํ•ด ์ด์ž‘์—…์„ ์™„๋ฃŒํ•  ์ˆ˜ ์žˆ๋‹ค.

List<Dish> slicedMenu2 
	= specialMenu.stream()
				 .dropWhile(dish -> dish.getCalories() < 320)
				 .collect(toList())

ํ”„๋ ˆ๋””์ผ€์ดํŠธ๊ฐ€ ๊ฑฐ์ง“์ด ๋˜๋ฉด ๊ทธ ์ง€์ ์—์„œ ์ž‘์—…์„ ์ค‘๋‹จํ•˜๊ณ  ๋‚จ์€ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. dropWhile์€ ๋ฌดํ•œํ•œ ๋‚จ์€ ์š”์†Œ๋ฅผ ๊ฐ€์ง„ ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์—์„œ๋„ ๋™์ž‘ํ•œ๋‹ค.

5.2.2 ์ŠคํŠธ๋ฆผ ์ถ•์†Œ

์ŠคํŠธ๋ฆผ์€ ์ฃผ์–ด์ง„ ๊ฐ’ ์ดํ•˜์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ–๋Š” ์ƒˆ๋กœ์šด ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” limit(n) ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค. ์ŠคํŠธ๋ฆผ์ด ์ •๋ ฌ๋˜์–ด ์žˆ์œผ๋ฉด ์ตœ๋Œ€ ์š”์†Œ n๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

List<Dish> dishes = specialMenu.stream()
							   .filter(dish -> dish.getCalories() > 300)
							   .limit(3)
							   .collect(toList()); 


์ •๋ ฌ๋˜์ง€ ์•Š์€ ์ŠคํŠธ๋ฆผ(์˜ˆ๋ฅผ ๋“ค๋ฉด ์†Œ์Šค๊ฐ€ Set)์—๋„ limit๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์†Œ์Šค๊ฐ€ ์ •๋ ฌ๋˜์–ด์žˆ์ง€ ์•Š์•˜๋‹ค๋ฉด limit์˜ ๊ฒฐ๊ณผ๋„ ์ •๋ ฌ๋˜์ง€ ์•Š์€์ƒํƒœ๋กœ ๋ฐ˜ํ™˜๋œ๋‹ค.

5.2.3 ์š”์†Œ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

์ŠคํŠธ๋ฆผ์€ ์ฒ˜์Œ n๊ฐœ ์š”์†Œ๋ฅผ ์ œ์™ธํ•œ ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” skip(n) ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค.

List<Dish> dishes = menu.stream()
						.filter(d -> d.getCalories() > 300)
						.skip(2)
						.collect(toList());

ํ€ด์ฆˆ 5-1. ํ•„ํ„ฐ๋ง

// ์ŠคํŠธ๋ฆผ์„ ์ด์šฉํ•ด์„œ ์ฒ˜์Œ ๋“ฑ์žฅํ•˜๋Š” ๋‘ ๊ณ ๊ธฐ ์š”๋ฆฌ๋ฅผ ํ•„ํ„ฐ๋งํ•˜์‹œ์˜ค.
List<Dish> dishes =
	menu.stream()
		.filter(d -> d.getType() == Dish.Type.MEAT)
		.limit(2)
		.collect(toList());

๐Ÿ“– 5.3 ๋งคํ•‘

5.3.1 ์ŠคํŠธ๋ฆผ์˜ ๊ฐ ์š”์†Œ์— ํ•จ์ˆ˜ ์ ์šฉํ•˜๊ธฐ

์ŠคํŠธ๋ฆผ์€ ํ•จ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” map ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค. ์ธ์ˆ˜๋กœ ์ œ๊ณต๋œ ํ•จ์ˆ˜๋Š” ๊ฐ ์š”์†Œ์— ์ ์šฉ๋˜๋ฉฐ ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•œ ๊ฒฐ๊ณผ๊ฐ€ ์ƒˆ๋กœ์šด ์š”์†Œ๋กœ ๋งคํ•‘๋œ๋‹ค.

// ์š”๋ฆฌ๋ช…์„ ์ถ”์ถœํ•˜๋Š” ์ฝ”๋“œ
List<String> dishNames = menu.stream()
					 		  .map(Dish::getName)
					 		  .collect(toList());

getName์€ ๋ฌธ์ž์—ด์„๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ map ๋ฉ”์„œ๋“œ์˜ ์ถœ๋ ฅ ์ŠคํŠธ๋ฆผ์€ Stream<String> ํ˜•์‹์„ ๊ฐ–๋Š”๋‹ค.

// ๊ฐ ์š”๋ฆฌ๋ช…์˜ ๊ธธ์ด๋ฅผ ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?
List<Integer> dishNameLengths = menu.stream()
									.map(Dish::getName)
									.map(String::length)
									.collect(toList());

5.3.2 ์ŠคํŠธ๋ฆผ ํ‰๋ฉดํ™”

["Hello", "World"] ๋ฆฌ์ŠคํŠธ๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ฒฐ๊ณผ๋กœ ["H", "e", "ใ…ฃ", V , "W", "r", d']๋ฅผํฌํ•จํ•˜๋Š” ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋ฐ˜ํ™˜๋˜์–ด์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

words.stream()
	 .map(word -> word.split(""))
	 .distinct()
	 .collect(toList());

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ๊ฐํ–ˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ map์œผ๋กœ ์ „๋‹ฌํ•œ ๋žŒ๋‹ค๋Š” ๊ฐ ๋‹จ์–ด์˜ String[](๋ฌธ์ž์—ด ๋ฐฐ์—ด)์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ์ ์ด ๋ฌธ์ œ๋‹ค. ๋”ฐ๋ผ์„œ map ๋ฉ”์†Œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์ŠคํŠธ๋ฆผ์˜ ํ˜•์‹์€ Stream<String[]>์ด๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ๋ฌธ์ž์—ด์˜ ์ŠคํŠธ๋ฆผ์„ ํ‘œํ˜„ํ•  Stream<String>์ด๋‹ค.

flatMap์ด๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ด๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

map๊ณผ Arrays.stream ํ™œ์šฉ

๋ฌธ์ž์—ด ๋ฐฐ์—ด์„ ๋ฐ›์•„ ๋ฌธ์ž์—ด ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„์•ผ ํ•œ๋‹ค.
๊ทธ ์—ญํ• ์„ Arrays.stream๊ฐ€ ํ•ด์ค€๋‹ค.

String[] arrayOfWords = {"Goodbye", "World"};
Stream<String> streamOfwords = Arrays.stream(arrayOfWords);

์œ„ ์˜ˆ์ œ์˜ ํŒŒ์ดํ”„๋ผ์ธ์— Arrays.stream() ๋ฉ”์„œ๋“œ๋ฅผ ์ ์šฉํ•ด๋ณด์ž.

words.stream()
	 .map(word -> word.split("")) // ๊ฐ ๋‹จ์–ด๋ฅผ ๊ฐœ๋ณ„ ๋ฌธ์ž์—ด ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ 
	 .map(Arrays::stream) // ๊ฐ ๋ฐฐ์—ด์„ ๋ณ„๋„์˜ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ƒ์„ฑ 
	 .distinct()
	 .collect(toList());

List<Stream<String>>๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š๋Š”๋‹ค.
๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๋จผ์ € ๊ฐ ๋‹จ์–ด๋ฅผ ๊ฐœ๋ณ„ ๋ฌธ์ž์—ด๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฐฐ์—ด๋กœ ๋งŒ๋“  ๋‹ค์Œ์— ๊ฐ ๋ฐฐ
์—ด์„ ๋ณ„๋„์˜ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

flatMap ์‚ฌ์šฉ

List<String> uniqueCharacters = 
	words.stream()
		 .map(word -> word.split("")) // ๊ฐ ๋‹จ์–ด๋ฅผ ๊ฐœ๋ณ„ ๋ฌธ์ž๋ฅผ ํฌํ•จํžˆ๋Š” ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ 
		 .flatMap(Arrays::rstream) // ์ƒ์„ฑ๋œ ์ŠคํŠธ๋ฆผ์„ ํ•˜๋‚˜์˜ ์ŠคํŠธ๋ฆผ์œผ๋กœ ํ‰๋ฉดํ™” 
		 .distinct()
		 .collect(toList());

map(Arrays::stream)๊ณผ ๋‹ฌ๋ฆฌ flatMap์€ ํ•˜๋‚˜์˜ ํ‰๋ฉดํ™”๋œ ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

ํ€ด์ฆˆ 5-2 ๋งคํ•‘

  1. ์ˆซ์ž ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ ๊ฐ ์ˆซ์ž์˜ ์ œ๊ณฑ๊ทผ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์‹œ์˜ค. ์˜ˆ๋ฅผ๋“ค์–ด [1, 2, 3, 4, 5]๊ฐ€์ฃผ์–ด์ง€๋ฉด [1. 4, 9, 16, 25]๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

์ •๋‹ต

List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> collect = nums.stream()
                			.map(num -> num * num)
                			.collect(Collectors.toList());
  1. ๋‘ ๊ฐœ์˜์ˆซ์ž ๋ฆฌ์ŠคํŠธ๊ฐ€ ์žˆ์„ ๋•Œ ๋ชจ๋“  ์ˆซ์ž์Œ์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์‹œ์˜ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‘ ๊ฐœ์˜ ๋ฆฌ์ŠคํŠธ [1, 2, 3]๊ณผ [3, 4]๊ฐ€ ์ฃผ์–ด์ง€๋ฉด [(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)]๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

์ •๋‹ต

List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> pairs = 
			numbers1.stream()
            		.flatMap(i -> numbers2.stream().map(j -> new int[]{i, j}))
                    .collect(Collectors.toList());
  1. ์ด์ „ ์˜ˆ์ œ์—์„œ ํ•ฉ์ด 3์œผ๋กœ ๋‚˜๋ˆ„์–ด๋–จ์–ด์ง€๋Š” ์Œ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ? ์˜ˆ๋ฅผ๋“ค์–ด (2,4), (3,3)์„๋ฐ˜ํ™˜ํ•ด์•ผํ•œ๋‹ค.
1) ์ฑ… ๋ฐฉ๋ฒ•
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
        List<Integer> numbers2 = Arrays.asList(3, 4);
        List<int[]> pairs = numbers1.stream()
                .flatMap(i -> numbers2.stream()
                        .filter(j -> (i+j) % 3 == 0)
                        .map(j -> new int[]{i, j}))
                .collect(Collectors.toList());

2) ๋‚ด ๋ฐฉ๋ฒ•
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
        List<Integer> numbers2 = Arrays.asList(3, 4);
        List<int[]> pairs = numbers1.stream()
                .flatMap(i -> numbers2.stream().map(j -> new int[]{i, j}))
                .filter(i -> Arrays.stream(i).sum() % 3 == 0)
                .collect(Collectors.toList());

๐Ÿ“– 5.4 ๊ฒ€์ƒ‰๊ณผ ๋งค์นญ

5.4.1 ํ”„๋ ˆ๋””์ผ€์ดํŠธ๊ฐ€ ์ ์–ด๋„ ํ•œ ์š”์†Œ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ

ํ”„๋ ˆ๋””์ผ€์ดํŠธ๊ฐ€ ์ฃผ์–ด์ง„ ์ŠคํŠธ๋ฆผ์—์„œ ์ ์–ด๋„ ํ•œ ์š”์†Œ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•  ๋•Œ anyMatch ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ์ฝ”๋“œ๋Š” menu์— ์ฑ„์‹์š”๋ฆฌ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ์˜ˆ์ œ๋‹ค.

if(menu.stream().anyMatch(Dish::isVegetarian)) {
	System.out.println("The menu is (somewhat) vegetarian friendly!!");
}

5.4.2 ํ”„๋ ˆ๋””์ผ€์ดํŠธ๊ฐ€ ๋ชจ๋“  ์š”์†Œ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์‚ฌ

์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ๊ฐ€ ์ฃผ์–ด์ง„ ํ”„๋ ˆ๋””์ผ€์ดํŠธ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์‚ฌํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฉ”๋‰ด๊ฐ€ ๊ฑด๊ฐ•์‹(๋ชจ๋“  ์š”๋ฆฌ๊ฐ€ 1000์นผ๋กœ๋ฆฌ ์ดํ•˜๋ฉด ๊ฑด๊ฐ•์‹์œผ๋กœ ๊ฐ„์ฃผ) ์ธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

boolean isHealthy = menu.stream()
						.allMatch(dish -> dish.getCalories() < 1000);

NONEMATCH

noneMatch๋Š” allMatch์™€ ๋ฐ˜๋Œ€ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ฆ‰, noneMatch๋Š” ์ฃผ์–ด์ง„ ํ”„๋ ˆ๋””์ผ€์ดํŠธ์™€ ์ผ์น˜ํ•˜๋Š”์š”์†Œ๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

boolean isHealthy = menu.stream()
						.noneMatch(d -> d.getCalories() >= 1000);

anyMatch, allMatch, noneMatch ์„ธ ๋ฉ”์„œ๋“œ๋Š” ์ŠคํŠธ๋ฆผ ์‡ผํŠธ์„œํ‚ท ๊ธฐ๋ฒ•๏ผŒ์ฆ‰ ์ž๋ฐ”์˜ &&๏ผŒ||์™€ ๊ฐ™์€ ์—ฐ์‚ฐ์„ ํ™œ์šฉํ•œ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด if(false && true && true) ๋ผ๋ฉด ์ฒซ๋ฒˆ์งธ false๊ฐ€ ๋‚˜์˜ค๋ฉด ๋ฐ”๋กœ if๋ฌธ ๊ฒ€์‚ฌ๋ฅผ ๋๋‚ธ๋‹ค.(๋’ค์— true๋Š” ๋ณด์ง€๋„ ์•Š์Œ)

5.4.3 ์š”์†Œ ๊ฒ€์ƒ‰

findAny ๋ฉ”์„œ๋“œ๋Š” ํ˜„์žฌ ์ŠคํŠธ๋ฆผ์—์„œ ์ž„์˜์˜ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ์ฝ”๋“œ์ฒ˜๋Ÿผ filter์™€ findAny๋ฅผ ์ด์šฉํ•ด์„œ ์ฑ„์‹์š”๋ฆฌ๋ฅผ ์„ ํƒํ• ์ˆ˜ ์žˆ๋‹ค.

Optional<Dish> dish = 
	menu.stream()
		.filter(Dish::isVegetarian)
		.findAny();

์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ์€ ๋‚ด๋ถ€์ ์œผ๋กœ ๋‹จ์ผ ๊ณผ์ •์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ตœ์ ํ™”๋œ๋‹ค. ์ฆ‰, ์‡ผํŠธ์„œํ‚ท์„ ์ด์šฉํ•ด์„œ ๊ฒฐ๊ณผ๋ฅผ ์ฐพ๋Š” ์ฆ‰์‹œ ์‹คํ–‰์„ ์ข…๋ฃŒํ•œ๋‹ค.

Optional ์ด๋ž€?

Optional<T> ํด๋ž˜์Šค(java.util.Optional)๋Š” ๊ฐ’์˜ ์กด์žฌ๋‚˜ ๋ถ€์žฌ ์—ฌ๋ถ€๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ ํด๋ž˜์Šค๋‹ค. ์ด์ „ ์˜ˆ์ œ์—์„œ findAny๋Š” ์•„๋ฌด ์š”์†Œ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. null์€ ์‰ฝ๊ฒŒ ์—๋Ÿฌ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ž๋ฐ” 8 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค๊ณ„์ž๋Š”Optional<T>๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ์ž์„ธํ•œ๊ฑด 10์žฅ์—์„œ ์•Œ์•„๋ณด์ž.

๋‹ค์Œ ์‚ฌ์‹ค๋งŒ ์•Œ์•„๋‘์ž!

  • isPresent()๋Š” Optional์ด ๊ฐ’์„ ํฌํ•จํ•˜๋ฉด ์ฐธ(true)์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๊ฐ’์„ ํฌํ•จํ•˜์ง€ ์•Š์œผ๋ฉด ๊ฑฐ์ง“(false)์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ifPresent (Consumer<T>) block)์€ ๊ฐ’์ด ์žˆ์œผ๋ฉด ์ฃผ์–ด์ง„ ๋ธ”๋ก์„ ์‹คํ–‰ํ•œ๋‹ค.
  • T get ()์€ ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๊ฐ’์ด ์—†์œผ๋ฉด NoSuchElementException์„ ์ผ์œผํ‚จ๋‹ค.
  • T orElse(T other)๋Š” ๊ฐ’์ด ์žˆ์œผ๋ฉด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ ๏ผŒ๊ฐ’์ด ์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
menu.stream()
	.filter(Dish::isVegetarian)
	.findAny() // Optional<Dish> ๋ฐ˜ํ™˜
	.ifPresent(dish -> System.out.println(dish.getName()); 
    // ๊ฐ’์ด ์žˆ์œผ๋ฉด ์ถœ๋ ฅ๋˜๊ณ  ์—†์œผ๋ฉด ์•„๋ฌด ์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค.

5.4.4 ์ฒซ ๋ฒˆ์งธ ์š”์†Œ ์ฐพ๊ธฐ

์ŠคํŠธ๋ฆผ์—์„œ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ฅผ ์ฐพ์œผ๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?

List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstSquareDivisibleByThree = 
		someNumbers.stream()
				   .map(n -> n * n)
				   .filter(n -> n % 3 == 0)
				   .findFirst(); // 9

findFirst VS findAny
๋ณ‘๋ ฌ ์‹คํ–‰์—์„œ๋Š” ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ ์–ด๋ ต๋‹ค. ๋”ฐ๋ผ์„œ ์š”์†Œ์˜ ๋ฐ˜ํ™˜ ์ˆœ์„œ๊ฐ€ ์ƒ๊ด€์—†๋‹ค๋ฉด ๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ์—์„œ๋Š” ์ œ์•ฝ์ด ์ ์€ findAny๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

๐Ÿ“– 5.5 ๋ฆฌ๋“€์‹ฑ

๋ฆฌ๋“€์‹ฑ ์—ฐ์‚ฐ : ๋ชจ๋“  ์ŠคํŠธ๋ฆผ ์š”์†Œ๋ฅผ ์ฒ˜๋ฆฌํ•ด์„œ ๊ฐ’์œผ๋กœ ๋„์ถœ
ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด ์šฉ์–ด๋กœ๋Š” ์ด ๊ณผ์ •์ด ๋งˆ์น˜ ์ข…์ด(์šฐ๋ฆฌ์˜ ์ŠคํŠธ๋ฆผ)๋ฅผ ์ž‘์€ ์กฐ๊ฐ์ด ๋  ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•ด์„œ ์ ‘๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๋‹ค๋Š” ์˜๋ฏธ๋กœ ํด๋“œ(fold)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

5.5.1 ์š”์†Œ์˜ ํ•ฉ

int sum = 0; 
for (int x : numbers) { 
	sum += x;
}

// ์ŠคํŠธ๋ฆผ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
int sum = numbers.stream().reduce(0, (a, b) -> a + b); 

์ฒซ๋ฒˆ์งธ ์š”์†Œ : ์ดˆ๊นƒ๊ฐ’ 0
๋‘๋ฒˆ์งธ ์š”์†Œ : BinaryOperator<T>

์ดˆ๊นƒ๊ฐ’ ์—†์Œ

Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));

์ดˆ๊นƒ๊ฐ’์ด ์—†์œผ๋ฉด ์™œ Optional์„ ๋ฐ˜ํ™˜ํ• ๊นŒ?
์ดˆ๊นƒ๊ฐ’๋„ ์—†๊ณ  ์ŠคํŠธ๋ฆผ์— ์•„๋ฌด ์š”์†Œ๋„ ์—†๋‹ค๋ฉด ํ•ฉ๊ณ„๊ฐ€ ์—†์Œ์„ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ๋„๋ก Optional ๊ฐ์ฒด๋กœ ๊ฐ์‹ผ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

5.5.2 ์ตœ๋Œ“๊ฐ’๊ณผ ์ตœ์†Ÿ๊ฐ’

// ์ตœ๋Œ€๊ฐ’
Optional<Integer> max = numbers.stream().reduce(Integer::max);
// ์ตœ์†Ÿ๊ฐ’
Optional<Integer> min = numbers.stream().reduce(Integer::min);

ํ€ด์ฆˆ 5-3 ๋ฆฌ๋“€์Šค

map๊ณผ reduce ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ŠคํŠธ๋ฆผ์˜ ์š”๋ฆฌ ๊ฐœ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜์‹œ์˜ค.

int count = menu.stream()
				.map(d -> 1)
                .reduce(0, (a, b) -> a + b);

reduce ๋ฉ”์„œ๋“œ์˜ ์žฅ์ ๊ณผ ๋ณ‘๋ ฌํ™”

๋ฐ˜๋ณต์ ์ธ ํ•ฉ๊ณ„์—์„œ๋Š” sum ๋ณ€์ˆ˜๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์‰ฝ๊ฒŒ ๋ณ‘๋ ฌํ™”ํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ๊ฐ•์ œ์ ์œผ๋กœ ๋™๊ธฐํ™”์‹œํ‚ค๋”๋ผ๋„ ๊ฒฐ๊ตญ ๋ณ‘๋ ฌํ™”๋กœ ์–ป์–ด์•ผ ํ•  ์ด๋“์ด ์Šค๋ ˆ๋“œ ๊ฐ„์˜ ์†Œ๋ชจ์ ์ธ ๊ฒฝ์Ÿ ๋•Œ๋ฌธ์— ์ƒ์‡„๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค. ์ฆ‰ ์ด ์ž‘์—…์„ ๋ณ‘๋ ฌํ™”ํ•˜๋ ค๋ฉด ์ž…๋ ฅ์„ ๋ถ„ํ• ํ•˜๊ณ , ๋ถ„ํ• ๋œ ์ž…๋ ฅ์„ ๋”ํ•œ ๋‹ค์Œ์—, ๋”ํ•œ ๊ฐ’์„ ๊ณ ์ณ์•ผ ํ•œ๋‹ค.
ํ•˜์ง€๋งŒ ์ŠคํŠธ๋ฆผ์„ ์ด์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ๋ณ‘๋ ฌํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.

int sum = numbers.parallelStream(),reduce(0, Integer::sum);

์œ„ ์ฝ”๋“œ๋ฅผ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๋ ค๋ฉด ๋Œ€๊ฐ€๋ฅผ ์ง€๋ถˆํ•ด์•ผ ํ•œ๋‹ค. ์ฆ‰, reduce์— ๋„˜๊ฒจ์ค€ ๋žŒ๋‹ค์˜ ์ƒํƒœ(์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๊ฐ™์€)๊ฐ€ ๋ฐ”๋€Œ์ง€ ๋ง์•„์•ผ ํ•˜๋ฉฐ, ์—ฐ์‚ฐ์ด ์–ด๋–ค์ˆœ์„œ๋กœ ์‹คํ–‰๋˜๋”๋ผ๋„ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ๊ตฌ์กฐ์—ฌ์•ผ ํ•œ๋‹ค.

์ŠคํŠธ๋ฆผ ์—ฐ์‚ฐ : ์ƒํƒœ ์—†์Œ๊ณผ ์ƒํƒœ ์žˆ์Œ

map, filter ๋“ฑ์€ ์ž…๋ ฅ ์ŠคํŠธ๋ฆผ์—์„œ ๊ฐ ์š”์†Œ๋ฅผ ๋ฐ›์•„ 0 ๋˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅ ์ŠคํŠธ๋ฆผ์œผ๋กœ๋ณด๋‚ธ๋‹ค. ๋”ฐ๋ผ์„œ (์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ๋žŒ๋‹ค๋‚˜ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๊ฐ€ ๋‚ด๋ถ€์ ์ธ ๊ฐ€๋ณ€ ์ƒํƒœ๋ฅผ ๊ฐ–์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฐ€์ •ํ•˜์—) ์ด๋“ค์€ ๋ณดํ†ต ์ƒํƒœ๊ฐ€ ์—†๋Š”, ์ฆ‰ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ฐ–์ง€ ์•Š๋Š” ์—ฐ์‚ฐ(stateless operation)์ด๋‹ค.

ํ•˜์ง€๋งŒ reduce, sum, max ๊ฐ™์€ ์—ฐ์‚ฐ์€ ๊ฒฐ๊ณผ๋ฅผ ๋ˆ„์ ํ•  ๋‚ด๋ถ€ ์ƒํƒœ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์˜ˆ์ œ์˜ ๋‚ด๋ถ€ ์ƒํƒœ๋Š” ์ž‘์€๊ฐ’์ด๋‹ค. ์šฐ๋ฆฌ ์˜ˆ์ œ์—์„œ๋Š” int ๋˜๋Š” double์„ ๋‚ด๋ถ€ ์ƒํƒœ๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค. ์ŠคํŠธ๋ฆผ์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ์š”์†Œ์ˆ˜์™€ ๊ด€๊ณ„์—†์ด ๋‚ด๋ถ€ ์ƒํƒœ์˜ ํฌ๊ธฐ๋Š” ํ•œ์ •๋˜์–ด ์žˆ๋‹ค.

๋ฐ˜๋ฉด sorted๋‚˜ distinct ๊ฐ™์€ ์—ฐ์‚ฐ์€ filter๋‚˜ map์ฒ˜๋Ÿผ ์ŠคํŠธ๋ฆผ์„ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•„ ๋‹ค๋ฅธ ์ŠคํŠธ๋ฆผ์„ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ sorted๋‚˜ distinct๋Š” filter๋‚˜map๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค. ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋ฅผ ์ •๋ ฌํ•˜๊ฑฐ๋‚˜ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๋ ค๋ฉด ๊ณผ๊ฑฐ์˜ ์ด๋ ฅ์„ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์–ด๋–ค์š”์†Œ๋ฅผ ์ถœ๋ ฅ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋ชจ๋“  ์š”์†Œ๊ฐ€ ๋ฒ„ํผ์— ์ถ”๊ฐ€๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์ €์žฅ์†Œ ํฌ๊ธฐ๋Š” ์ •ํ•ด์ ธ์žˆ์ง€ ์•Š๋‹ค. ๋”ฐ๋ผ์„œ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์˜ ํฌ๊ธฐ๊ฐ€ ํฌ๊ฑฐ๋‚˜ ๋ฌดํ•œ์ด๋ผ๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ์—ฐ์‚ฐ์„ ๋‚ด๋ถ€์ƒํƒœ๋ฅผ ๊ฐ–๋Š” ์—ฐ์‚ฐ์ด๋ผ ํ•œ๋‹ค.

์ •๋ฆฌํ•˜์ž๋ฉด map, filter์ฒ˜๋Ÿผ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ฐ–์ง€ ์•Š๋Š” ๋ฉ”์„œ๋“œ์™€ reduce, sum, max, sorted, distinct์ฒ˜๋Ÿผ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์กด์žฌํ•œ๋‹ค.

๐Ÿ“– 5.7 ์ˆซ์žํ˜• ์ŠคํŠธ๋ฆผ

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฉ”๋‰ด์˜ ์นผ๋ฆฌ๋กœ ํ•ฉ๊ณ„๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค.

int calories = menu.stream()
					.map(Dish::getCalories)
  					.reduce(0, Integer::sum);

์‚ฌ์‹ค ์œ„ ์ฝ”๋“œ์—๋Š” ๋ฐ•์‹ฑ ๋น„์šฉ์ด ์ˆจ์–ด์žˆ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ ํ•ฉ๊ณ„๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์ „์— Integer๋ฅผ ๊ธฐ๋ณธํ˜•์œผ๋กœ ์–ธ๋ฐ•์‹ฑ ํ•ด์•ผํ•œ๋‹ค.
๋‹ค์Œ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ง์ ‘ sum๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์ง€ ์•Š์„๊นŒ?

int calories = menu.stream()
					.map(Dish::getCalories)
  					.sum();

ํ•˜์ง€๋งŒ ์ด ์ฝ”๋“œ๋„ sum()๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋‹ค. map์ด Stream<T>๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ ํ˜•์‹์€ Integer์ง€๋งŒ ์ธํ„ฐํŽ˜์ด์Šค์—๋Š” sum ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๋‹ค.
์™œ sum ๋ฉ”์„œ๋“œ๊ฐ€ ์—†์„๊นŒ? ์˜ˆ๋ฅผ๋“ค์–ด menu์ฒ˜๋Ÿผ Stream<Dish> ํ˜•์‹์˜ ์š”์†Œ๋งŒ ์žˆ๋‹ค๋ฉด sum์ด๋ผ๋Š” ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋Ÿผ ๊ณ„์† ๋ฐ•์‹ฑ ๋น„์šฉ์„ ๊ฐ์ˆ˜ํ•˜๊ณ  reduce๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ?
๋‹คํ–‰ํžˆ ์Šคํ”„๋ฆผ API์—์„œ๋Š” ๊ธฐ๋ณธํ˜• ํŠนํ™” ์ŠคํŠธ๋ฆผ์„ ์ œ๊ณตํ•œ๋‹ค.

5.7.1 ๊ธฐ๋ณธํ˜• ํŠนํ™” ์ŠคํŠธ๋ฆผ

IntStream, DoubleStream, LongStream์ด ์กด์žฌํ•œ๋‹ค.

์ˆซ์ž ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋งคํ•‘

mapToInt, mapToDouble, mapToLong ์„ธ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.
map๊ณผ ์ •ํ™•ํžˆ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ๏ผŒStream<T> ๋Œ€์‹  ํŠนํ™”๋œ ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.(IntStream)

int calories = menu.stream() // Stream<Dish> ๋ฐ˜ํ™˜
				   .mapToInt(Dish::getCalories) // IntStram๋ฐ˜ํ™˜
				   .sum();

๊ฐ์ฒด ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณต์›ํ•˜๊ธฐ

์ˆซ์ž ์ŠคํŠธ๋ฆผ์„ ์›์ƒํƒœ์ธ ํŠนํ™”๋˜์ง€ ์•Š์€ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณต์›ํ•  ์ˆ˜ ์žˆ์„๊นŒ? boxed

IntStrea mintStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed(); // ์ˆซ์ž ์ŠคํŠธ๋ฆผ์„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜

๊ธฐ๋ณธ๊ฐ’: Optionallnt

์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ์ตœ๋Œ€, ์ตœ์†Œ๋Š” ์—†์„ ๊ฒƒ์ด๋‹ค. ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

Optionallnt maxCalories = menu.stream()
							  .mapToInt(Dish::getCalories)
							  .max();

Optionallnt๋กœ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋œ๋‹ค. ์ตœ๋Œ€๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ๊ฐ’์„ ๋ช…์‹œ์ ์œผ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

int max = maxCalories.orElse(1);

5.7.2 ์ˆซ์ž ๋ฒ”์œ„

IntStream evenNumbers = IntStream.rangeClosed(1, 100) // [1,100] ํฌํ•จ
								.filter(n -> n % 2 == 0);
System.out.println(evenNumbers.count()); // 50๊ฐœ

range(1,100) // 49๊ฐœ, (1,100) ๋ฏธํฌํ•จ

5.7.3 ์ˆซ์ž ์ŠคํŠธ๋ฆผ ํ™œ์šฉ : ํ”ผํƒ€๊ณ ๋ผ์Šค ์ˆ˜

์ƒ๋žตํ•˜๊ฒ ๋œธ.. ๋ฐฐ๋ณด๋‹ค ๋ฐฐ๊ผฝ์ด ๋” ์ปค์ง€๋Š”๊ฑฐ ๊ฐ™์•„์„œ ๊ฐœ์ธ์ ์œผ๋กœ ๊ณต๋ถ€!

๐Ÿ“– 5.8 ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ

์ด ์ ˆ์—์„œ๋Š” ์ผ๋ จ์˜ ๊ฐ’, ๋ฐฐ์—ด, ํŒŒ์ผ, ์‹ฌ์ง€์–ด ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•œ๋‹ค.

5.8.1 ๊ฐ’์œผ๋กœ ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ

์ž„์˜์˜ ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” ์ •์  ๋ฉ”์„œ๋“œ Stream.of๋ฅผ ์ด์šฉํ•ด์„œ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

Stream<String> stream = Stream.of("Modern", "Java", "In", "Action");
stream.map(String::toUpperCase).forEach(System.out::println);

// empty ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ŠคํŠธ๋ฆผ์„ ๋น„์šธ์ˆ˜ ์žˆ๋‹ค.
Stream<String> emptyStream = Stream.empty();

5.8.2 null์ด ๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋กœ ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ

์ž๋ฐ” 9 ์ด์ „์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด null์„ ํ™•์ธํ•ด์ค˜์•ผ ํ–ˆ๋‹ค.

String homeValue = System.getProperty("home");
Stream<String> homeValueStream = homeValue == null ? Stream.empty() : Stream.of(value);

getProperty : ์ž๋ฐ”๋ฅผ ์‹คํ–‰ํ•  ๋•Œ, ์‹คํ–‰๋˜๋Š” ๊ณณ์˜ ์ •๋ณด๋ฅผ ์–ป์–ด์˜ค๊ฑฐ๋‚˜ ์šด์˜์ฒด์ œ์˜ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ์‹คํ–‰ ์œ„์น˜์— ์žˆ๋Š” ํŒŒ์ผ์„ ์ฝ์–ด๋“œ๋ ค์•ผ ํ•˜๋Š”๋ฐ, ํ˜„์žฌ ์œ„์น˜๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• ๋“ฑ ์‹œ์Šคํ…œ์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ System.getProperty(key) ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
key๋Š” java ์‹œ์Šคํ…œ ์†์„ฑ๋ชฉ๋ก ๊ฒ€์ƒ‰ํ•˜๋ฉด ๋‚˜์˜จ๋‹ค.

ํ•˜์ง€๋งŒ ์ž๋ฐ” 9์ดํ›„์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

Stream<String> homeValueStream
	= Stream.ofNullable(System.getProperty("home"));

null์ด ๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ํฌํ•จํ•˜๋Š” ์ŠคํŠธ๋ฆผ๊ฐ’์„ flatMap๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ์ƒํ™ฉ์—์„œ๋Š” ์ด ํŒจํ„ด์„ ๋” ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Stream<String> values =
			Stream.of("config", "home", "user")
				  .flatMap(key -> Stream.ofNullable(System.getProperty(key)));

5.8.3 ๋ฐฐ์—ด๋กœ ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ

Arrays.stream์„ ์ด์šฉํ•˜๊ธฐ

int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum(); 

5.8.4. ํŒŒ์ผ๋กœ ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ

long uniqueWords = 0;
// AutoCloseable์ด๋ฏ€๋กœ tryโ€”finally๊ฐ€ ํ•„์š”์—†๋‹ค.
try(Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())) { 
	uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" "))) 
					   .distinct()
					   .count();
} catch (IOException e) {
	// ์˜ˆ์™ธ์ฒ˜๋ฆฌ
}

Paths.get("data.txt") : "data.txt"์— ํ•ด๋‹นํ•˜๋Š” Path ๊ฐ์ฒด ๋ฐ˜ํ™˜
Files.lines : ํ•ด๋‹น ๊ฒฝ๋กœ์— ์žˆ๋Š” ํŒŒ์ผ ์ฝ์–ด์„œ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ฐ˜ํ™˜

5.8.5 ํ•จ์ˆ˜๋กœ ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ

์ •์  ๋ฉ”์„œ๋“œ Stream.iterate์™€ Stream, generate๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๋‘ ์—ฐ์‚ฐ์„ ์ด์šฉํ•ด์„œ ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ, ์ฆ‰ ๊ณ ์ •๋œ ์ปฌ๋ ‰์…˜์—์„œ ๊ณ ์ •๋œ ํฌ๊ธฐ๋กœ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค์—ˆ๋˜ ๊ฒƒ๊ณผ๋Š” ๋‹ฌ๋ฆฌ ํฌ๊ธฐ๊ฐ€ ๊ณ ์ •๋˜์ง€ ์•Š์€ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
iterate์™€ generate์—์„œ ๋งŒ๋“  ์ŠคํŠธ๋ฆผ์€ ์š”์ฒญํ•  ๋•Œ๋งˆ๋‹ค ์ฃผ์–ด์ง„ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ’์„ ๋งŒ๋“ ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฌด์ œํ•œ์œผ๋กœ ๊ฐ’์„ ๊ณ„์‚ฐํ• ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ณดํ†ต ๋ฌดํ•œํ•œ ๊ฐ’์„ ์ถœ๋ ฅํ•˜์ง€ ์•Š๋„๋ก limit(n) ํ•จ์ˆ˜๋ฅผ ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

iterate ๋ฉ”์„œ๋“œ

Stream.iterate(0, n -> n + 2)
	  .limit(10)
	  .forEach(System.out::println);

์ดˆ๊ธฐ๊ฐ’ 0, ๋žŒ๋‹ค๋ฅผ ์ด์šฉํ•ด์„œ ๋ฌดํ•œํ•œ ์ง์ˆ˜ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
์ด๋Ÿฌํ•œ ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์„ ์–ธ๋ฐ”์šด๋“œ ์ŠคํŠธ๋ฆผ์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

ํ€ด์ฆˆ 5-4 ํ”ผ๋ณด๋‚˜์น˜์—ด ์ง‘ํ•ฉ

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55... ๊ฐ™์€ ์‹์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผ ํ• ๊นŒ?

Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]})
	.limit(10)
	.map(t -> t[0])
	.forEach(System.out::println);

์ž๋ฐ” 9์˜ iterate ๋ฉ”์†Œ๋“œ๋Š” ํ”„๋ ˆ๋””์ผ€์ดํŠธ๋ฅผ ์ง€์›ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด 0์—์„œ ์‹œ์ž‘ํ•ด์„œ 100๋ณด๋‹ค ํฌ๋ฉด์ˆซ์ž ์ƒ์„ฑ์„ ์ค‘๋‹จํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ์ฒ˜๋Ÿผ ๊ตฌํ˜„ํ• ์ˆ˜ ์žˆ๋‹ค.

IntStream.iterate(0, n -> n < 100, n -> n + 4)
		 .forEach(System.out::println);

๋‹ค์Œ๊ณผ ๊ฐ™์ด filter์„ ์ด์šฉํ•ด๋„ ๋˜์ง€ ์•Š์„๊นŒ?

IntStream.iterate(0, n -> n + 4)
		 .filter(n -> n < 100)
		 .forEach(System.out::println);

์•„์‰ฝ๊ฒŒ๋„ ์ด ์ฝ”๋“œ๋Š” ๋ฌดํ•œ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ ๋‹ค. filter ์ž…์žฅ์—์„œ๋Š” ์–ธ์ œ ์ด ์ž‘์—…์„ ์ค‘๋‹จํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ŠคํŠธ๋ฆผ ์‡ผํŠธ์„œํ‚ท์„ ์ง€์›ํ•˜๋Š” takeWhile์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด ํ•ด๋ฒ•์ด๋‹ค.

IntStream.iterate(0 , n - > n + 4)
		 .takeWhile(n -> n < 100)
		 .forEach(System.out::println);

generate ๋ฉ”์„œ๋“œ

iterate์™€ ๋‹ฌ๋ฆฌ generate๋Š” ์ƒ์‚ฐ๋œ ๊ฐ ๊ฐ’์„ ์—ฐ์†์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜์ง€ ์•Š๋Š”๋‹ค. generate๋Š” supplier<T>๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์•„์„œ ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ƒ์‚ฐํ•œ๋‹ค.

Stream.generate(Math::random)
	  .limit(5)
	  .forEach(System.out::println);

generate๋Š” ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•œ ๋ฐœํ–‰์ž(supplier : ๋ฉ”์„œ๋“œ ์ฐธ์กฐ Math.random)๋Š” ์ƒํƒœ๊ฐ€ ์—†๋Š” ๋ฉ”์„œ๋“œ, ์ฆ‰ ๋‚˜์ค‘์— ๊ณ„์‚ฐ์— ์‚ฌ์šฉํ•  ์–ด๋–ค ๊ฐ’๋„ ์ €์žฅํ•ด๋‘์ง€ ์•Š๋Š”๋‹ค.

ํ•˜์ง€๋งŒ ๋ฐœํ–‰์ž(supplier)๊ฐ€ ๋ฐ˜๋“œ์‹œ ์ƒํƒœ๊ฐ€ ์—†์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๋’ค์— ๋ถ€๋ถ„์—์„œ ์„ค๋ช…ํ•˜๊ฒ ์ง€๋งŒ ์ƒํƒœ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ(๋™์‹œ์„ฑ)์—์„œ ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.

iterate์—์„œ ์„ค๋ช…ํ•œ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด ์˜ˆ์ œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๊ฒƒ์ด๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฐ•์‹ฑ์—ฐ์‚ฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด IntStream์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ฉฐ IntStream์€ Supplier<T> ๋Œ€์‹  IntSupplier๋ฅผ ์ธ์ˆ˜๋กค ๋ฐ›๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์ž.

IntSupplier์€ ์ต๋ช… ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

IntStreamtwos = IntStream.generate(new IntSupplier() { 
	public int getAsInt() { 
		return 2;
	}
});

์ด๋Ÿฐ์‹์œผ๋กœ IntSupplier์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜์—ฌ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์„ ๊ตฌํ˜„ํ•ด๋ณด์ž!

IntSupplierfib = new IntSupplier() { 
	private int previous = 0; 
	private int current = 1; 
	public int getAsInt() {
		int oldPrevious = this.previous;
		int nextValue = this.previous + this.current;
		this.previous = this.current;
		this.current = nextValue;
		return oldPrevious;
	}
};
IntStream.generate(fib).limit(10).forEach(System.out::println);

IntSupplier ๊ฐ์ฒด์˜ ์ƒํƒœ๋Š” ๊ฐ€๋ณ€์ƒํƒœ์ด๋‹ค. ์ธ์Šคํ„ด์Šค ํ•„๋“œ์— ๊ฐ’์ด ๊ณ„์† ๋ณ€ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์•ž์—์„œ ๋งํ–ˆ๋“ฏ์ด ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ ‘๊ทผํ•˜์˜€์„ ๋•Œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค.

๋ฐ˜๋Œ€๋กœ iterate๋Š” ๋ถˆ๋ณ€์ƒํƒœ๋ฅผ ์œ ์ง€ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ŠคํŠธ๋ฆผ์„ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ ์˜ฌ๋ฐ”๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์–ป์œผ๋ ค๋ฉด ๋ถˆ๋ณ€ ์ƒํƒœ ๊ธฐ๋ฒ•์„ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋Š” 7์žฅ์—์„œ ๋ฐฐ์šฐ๋„๋ก ํ•˜์ž!

๋ฌดํ•œ์ŠคํŠธ๋ฆผ์—์„œ๋Š” limit์ด์šฉํ•ด ๋ช…์‹œ์ ์œผ๋กœ ์ŠคํŠธ๋ฆผ ํฌ๊ธฐ๋ฅผ ์ œํ•œ ํ•ด์•ผํ•˜๋ฉฐ ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋Š” ๋ฌดํ•œ์ ์œผ๋กœ ๊ณ„์‚ฐ์ด ๋ฐ˜๋ณต๋˜๋ฏ€๋กœ ์ •๋ ฌํ•˜๊ฑฐ๋‚˜ ๋ฆฌ๋“€์Šคํ• ์ˆ˜ ์—†๋‹ค.





์ฐธ๊ณ ์ž๋ฃŒ)
๋ณธ ํฌ์ŠคํŒ…์€ ๋ชจ๋˜ ์ž๋ฐ” ์ธ ์•ก์…˜์„ ์ฐธ๊ณ ํ•˜์—ฌ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

profile
๋ฉˆ์ถ”์ง€ ์•Š๊ธฐ

0๊ฐœ์˜ ๋Œ“๊ธ€