Post

๐ŸฆŠ chap5. ์ŠคํŠธ๋ฆผ ํ™œ์šฉ

chap5. ์ŠคํŠธ๋ฆผ ํ™œ์šฉ

5.1 ํ•„ํ„ฐ๋ง

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

์ŠคํŠธ๋ฆผ ์ธํ„ฐํŽ˜์ด์Šค๋Š” filter ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค.

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

1
2
3
List<Dish> vegetarianMenu = menu.stream()
																.filter(Dish::isVegetarian) // ์ฑ„์‹ ์š”๋ฆฌ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ ์ฐธ์กฐ
																.collect(toList());

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

๊ณ ์œ  ์š”์†Œ๋กœ ์ด๋ฃจ์–ด์ง„ ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” distinct ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค.

๊ณ ์œ  ์—ฌ๋ถ€๋Š” ๊ฐ์ฒด์˜ hashCode, equals ๋กœ ๊ฒฐ์ •๋œ๋‹ค.

1
2
3
4
5
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 ํ”„๋ ˆ๋””์ผ€์ดํŠธ๋ฅผ ์ด์šฉํ•œ ์Šฌ๋ผ์ด์‹ฑ

์ž๋ฐ” 9๋Š” ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋„๋ก takeWhile, dropWhile ์ด๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค.

TAKEWHILE ํ™œ์šฉ

takeWhile ์„ ์ด์šฉํ•˜๋ฉด ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์„ ํฌํ•จํ•œ ๋ชจ๋“  ์ŠคํŠธ๋ฆผ์— ํ”„๋ ˆ๋””์ผ€์ดํŠธ๋ฅผ ์ ์šฉํ•ด ์ŠคํŠธ๋ฆผ์„ ์Šฌ๋ผ์ด์Šคํ•  ์ˆ˜ ์žˆ๋‹ค.

ํŠนํžˆ ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ด๋ฏธ ์ •๋ ฌ๋˜์–ด ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์ด์šฉํ•ด ๋ฐ˜๋ณต ์ž‘์—…์„ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
List<Dish> slicedMenu1
		= specialMenu.stream()
								 .takeWhile(dish -> dish.getCalories() < 320)
								 .collect(toList());

DROPWHILE ํ™œ์šฉ

dropWhile ์€ takeWhile ์˜ ์ •๋ฐ˜๋Œ€์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

dropWhile ์€ ํ”„๋ ˆ๋””์ผ€์ดํŠธ๊ฐ€ ์ฒ˜์Œ์œผ๋กœ ๊ฑฐ์ง“์ด ๋˜๋Š” ์ง€์ ๊นŒ์ง€ ๋ฐœ๊ฒฌ๋œ ์š”์†Œ๋ฅผ ๋ฒ„๋ฆฐ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‚จ์€ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

1
2
3
4
List<Dish> slicedMenu2
		= specialMenu.stream()
								 .dropWhile(dish -> dish.getCalories() < 320)
								 .collect(toList());

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

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

์ŠคํŠธ๋ฆผ์ด ์ •๋ ฌ๋˜์–ด ์žˆ์œผ๋ฉด ์ตœ๋Œ€ ์š”์†Œ n๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

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

ํ”„๋ ˆ๋””์ผ€์ดํŠธ์™€ ์ผ์น˜ํ•˜๋Š” ์ฒ˜์Œ ์„ธ ์š”์†Œ๋ฅผ ์„ ํƒํ•œ ๋‹ค์Œ์— ์ฆ‰์‹œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

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

n๊ฐœ ์ดํ•˜์˜ ์š”์†Œ๋ฅผ ํฌํ•จํ•˜๋Š” ์ŠคํŠธ๋ฆผ์—์„œ ํ˜ธ์ถœํ•˜๋ฉด ๋นˆ ์ŠคํŠธ๋ฆผ์ด ๋ฐ˜ํ™˜๋œ๋‹ค.

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

5.3 ๋งคํ•‘

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

ํ•จ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” map ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค.

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

1
2
3
List<String> dishNames = menu.stream()
														 .map(Dish::getName)
														 .collect(toList());

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

1
2
3
4
List<String> words = Arrays.asList("Modern", "Java", "In", "Action");
List<Integer> wordLengths = words.stream()
																 .map(String::length)
																 .collect(toList());

๊ฐ ๋‹จ์–ด๊ฐ€ ํฌํ•จํ•˜๋Š” ๊ธ€์ž ์ˆ˜์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

1
2
3
4
List<Integer> dishNameLengths = menu.stream()
																		.map(Dish::getName)
																		**.map(String::length)**
																		.collect(toList());

์ด๋ฒˆ์—” ๊ฐ ์š”๋ฆฌ๋ช…์˜ ๊ธธ์ด๋ฅผ ํฌํ•จํ•˜๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

๋ฆฌ์ŠคํŠธ์—์„œ ๊ณ ์œ  ๋ฌธ์ž๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ด๋ณด์ž.

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

1
2
3
4
words.stream()
		 .map(word -> word.split(""))
		 .distinct()
		 .collect(toList());

distinct ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€์ง€๋งŒ map ์œผ๋กœ ์ „๋‹ฌํ•œ ๋žŒ๋‹ค๋Š” String[] ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ์ ์ด ๋ฌธ์ œ์ด๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ๋ฌธ์ž์—ด์˜ ์ŠคํŠธ๋ฆผ์„ ํ‘œํ˜„ํ•  Stream<String> ์ด๋‹ค.

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

๋ฐฐ์—ด ์ŠคํŠธ๋ฆผ ๋Œ€์‹  ๋ฌธ์ž์—ด ์ŠคํŠธ๋ฆผ์ด ํ•„์š”ํ•˜๋‹ค.

๋ฌธ์ž์—ด์„ ๋ฐ›์•„ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“œ๋Š” Arrrays.stream() ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋‹ค.

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

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

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

๊ฒฐ๊ตญ ์ŠคํŠธ๋ฆผ ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์•˜๋‹ค.

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

flatMap ์‚ฌ์šฉ

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

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

flatMap ์€ ๊ฐ ๋ฐฐ์—ด์„ ์ŠคํŠธ๋ฆผ์ด ์•„๋‹ˆ๋ผ ์ŠคํŠธ๋ฆผ์˜ ์ฝ˜ํ…์ธ ๋กœ ๋งคํ•‘ํ•œ๋‹ค.

์ฆ‰ ํ•˜๋‚˜์˜ ํ‰๋ฉดํ™”๋œ ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ŠคํŠธ๋ฆผ์˜ ๊ฐ ๊ฐ’์„ ๋‹ค๋ฅธ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋งŒ๋“  ๋‹ค์Œ์— ๋ชจ๋“  ์ŠคํŠธ๋ฆผ์„ ํ•˜๋‚˜์˜ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

5.4 ๊ฒ€์ƒ‰๊ณผ ๋งค์นญ

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

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

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

boolean ์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ข… ์—ฐ์‚ฐ์ด๋‹ค.

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

allMatch๋Š” ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ๊ฐ€ ์ฃผ์–ด์ง„ ํ”„๋ ˆ๋””์ผ€์ดํŠธ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์‚ฌํ•œ๋‹ค.

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

NONEMATCH

noneMatch ๋Š” allMatch ์™€ ๋ฐ˜๋Œ€ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

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

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

์ด ์„ธ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋Š” ์ŠคํŠธ๋ฆผ ์‡ผํŠธ์„œํ‚ท ๊ธฐ๋ฒ•์„ ํ™œ์šฉํ•œ๋‹ค.

์ „์ฒด ์ŠคํŠธ๋ฆผ์„ ์ €์น˜ํ•˜์ง€ ์•Š์•˜๋”๋ผ๋„ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

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

findAny ๋ฉ”์„œ๋“œ๋Š” ํ˜„์žฌ ์ŠคํŠธ๋ฆผ์—์„œ ์ž„์˜์˜ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

์‡ผํŠธ์„œํ‚ท์„ ์ด์šฉํ•ด์„œ ๊ฒฐ๊ณผ๋ฅผ ์ฐพ๋Š” ์ฆ‰์‹œ ์‹คํ–‰์„ ์ข…๋ฃŒํ•œ๋‹ค.

Optional์ด๋ž€?

Optional<T> ํด๋ž˜์Šค๋Š” ๊ฐ’์˜ ์กด์žฌ๋‚˜ ๋ถ€์žฌ ์—ฌ๋ถ€๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ ํด๋ž˜์Šค์ด๋‹ค.

null ์ด ์‰ฝ๊ฒŒ ์—๋Ÿฌ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ž๋ฐ” 8 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค๊ณ„์ž๊ฐ€ ๋งŒ๋“ค์—ˆ๋‹ค.

  • isPresent()๋Š” Optional ์ด ๊ฐ’์„ ํฌํ•จํ•˜๋ฉด ์ฐธ, ์—†์œผ๋ฉด ๊ฑฐ์ง“์ด๋‹ค.
  • ifPresent(Consumer<T> block) ์€ ๊ฐ’์ด ์žˆ์œผ๋ฉด ์ฃผ์–ด์ง„ ๋ธ”๋ก์„ ์‹คํ–‰ํ•œ๋‹ค.
  • T get() ์€ ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์—†์œผ๋ฉด NoSuchElementException์„ ๋˜์ง„๋‹ค.
  • T orElse(T other)์€ ๊ฐ’์ด ์žˆ์œผ๋ฉด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๊ฐ’์ด ์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

์ผ๋ถ€ ์ŠคํŠธ๋ฆผ์—๋Š” ๋…ผ๋ฆฌ์ ์ธ ์•„์ดํ…œ ์ˆœ์„œ๊ฐ€ ์ •ํ•ด์ ธ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์Œ์€ ์ˆซ์ž ๋ฆฌ์ŠคํŠธ์—์„œ 3์œผ๋กœ ๋‚˜๋ˆ„์–ด ๋–จ์–ด์ง€๋Š” ์ฒซ ๋ฒˆ์งธ ์ œ๊ณฑ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

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

findFirst์™€ findAny ๋Š” ์–ธ์ œ ์‚ฌ์šฉํ•˜๋‚˜?

๋‘ ๋ฉ”์„œ๋“œ๊ฐ€ ์™œ ๋ชจ๋‘ ํ•„์š”ํ•œ๊ฐ€?

๋ฐ”๋กœ ๋ณ‘๋ ฌ์„ฑ ๋•Œ๋ฌธ์ด๋‹ค.

๋ณ‘๋ ฌ ์‹คํ–‰์—์„œ๋Š” ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ ์–ด๋ ต๋‹ค.

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

5.5 ๋ฆฌ๋“€์‹ฑ

์ŠคํŠธ๋ฆผ ์š”์†Œ๋ฅผ ์กฐํ•ฉํ•ด์„œ ๋” ๋ณต์žกํ•œ ์งˆ์˜๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฆฌ๋“€์‹ฑ ์—ฐ์‚ฐ์ด๋ผ๊ณ  ํ•œ๋‹ค.

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

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

๋‹ค์Œ์€ forEach ๋ฃจํ”„๋ฅผ ์ด์šฉํ•ด์„œ ๋ฆฌ์ŠคํŠธ์˜ ์ˆซ์ž ์š”์†Œ๋ฅผ ๋”ํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

1
2
3
4
5
// ๋ฆฌ์ŠคํŠธ์˜ ์ˆซ์ž ์š”์†Œ์˜ ํ•ฉ
int sum = 0;
for (int x : numbers) {
		sum += x;
}

nubmers ์˜ ๊ฐ ์š”์†Œ๋Š” ๊ฒฐ๊ณผ์— ๋ฐ˜๋ณต์ ์œผ๋กœ ๋”ํ•ด์ง„๋‹ค.

์ด ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌ ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋“  ์ˆซ์ž๋ฅผ ๊ณฑํ•˜๋Š” ์—ฐ์‚ฐ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด

๋‹ค์Œ์ฒ˜๋Ÿผ reduce ๋ฅผ ์ด์šฉํ•ด์„œ ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋”ํ•  ์ˆ˜ ์žˆ๋‹ค.

1
int sum = numbers.stream().reduce(0, (a, b) -> a + b);

reduce ๋Š” ๋‘ ์š”์†Œ๋ฅผ ์ธ์ž๋กœ ๊ฐ€์ง„๋‹ค.

  • ์ดˆ๊นƒ๊ฐ’ 0
  • ๋‘ ์š”์†Œ๋ฅผ ์กฐํ•ฉํ•ด์„œ ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋งŒ๋“œ๋Š” BinaryOperator<T>

reduce ๋Š” ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ๋ฅผ ์†Œ๋น„ํ•˜์—ฌ ๋ˆ„์ ๊ฐ’์œผ๋กœ ๋žŒ๋‹ค๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•œ๋‹ค.

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

์ดˆ๊นƒ๊ฐ’์„ ๋ฐ›์ง€ ์•Š๋„๋ก ์˜ค๋ฒ„๋กœ๋“œ๋œ reduce ๋ฅผ ์‚ดํŽด๋ณด์ž.

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

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

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

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

๋‹ค์Œ์ฒ˜๋Ÿผ reduce๋ฅผ ์ด์šฉํ•ด์„œ ์ŠคํŠธ๋ฆผ์˜ ์ตœ๋Œ“๊ฐ’๊ณผ ์ตœ์†Ÿ๊ฐ’์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

1
Optional<Integer> max = numbers.stream().reduce(Integer::max);
1
Optional<Integer> min = numbers.stream().reduce(Integer::min);

5.6 ์‹ค์ „ ์—ฐ์Šต

  1. 2011๋…„์— ์ผ์–ด๋‚œ ๋ชจ๋“  ํŠธ๋žœ์žญ์…˜์„ ์ฐพ์•„ ๊ฐ’์„ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ฆฌํ•˜์‹œ์˜ค.
  2. ๊ฑฐ๋ž˜์ž๊ฐ€ ๊ทผ๋ฌดํ•˜๋Š” ๋ชจ๋“  ๋„์‹œ๋ฅผ ์ค‘๋ณต ์—†์ด ๋‚˜์—ดํ•˜์‹œ์˜ค.
  3. ์ผ€์ž„๋ธŒ๋ฆฌ์ง€์—์„œ ๊ทผ๋ฌดํ•˜๋Š” ๋ชจ๋“  ๊ฑฐ๋ž˜์ž๋ฅผ ์ฐพ์•„์„œ ์ด๋ฆ„์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์‹œ์˜ค.
  4. ๋ชจ๋“  ๊ฑฐ๋ž˜์ž์˜ ์ด๋ฆ„์„ ์•ŒํŒŒ๋ฒณ์ˆœ์œผ๋กœ ์ •๋ ฌํ•ด์„œ ๋ฐ˜ํ™˜ํ•˜์‹œ์˜ค.
  5. ๋ฐ€๋ผ๋…ธ์— ๊ฑฐ๋ž˜์ž๊ฐ€ ์žˆ๋Š”๊ฐ€?
  6. ์ผ€์ž„๋ธŒ๋ฆฌ์ง€์— ๊ฑฐ์ฃผํ•˜๋Š” ๊ฑฐ๋ž˜์ž์˜ ๋ชจ๋“  ํŠธ๋žœ์žญ์…˜๊ฐ’์„ ์ถœ๋ ฅํ•˜์‹œ์˜ค.
  7. ์ „์ฒด ํŠธ๋žœ์žญ์…˜ ์ค‘ ์ตœ๋Œ“๊ฐ’์€ ์–ผ๋งˆ์ธ๊ฐ€?
  8. ์ „์ฒด ํŠธ๋žœ์žญ์…˜ ์ค‘ ์ตœ์†Ÿ๊ฐ’์€ ์–ผ๋งˆ์ธ๊ฐ€?

5.7 ์ˆซ์žํ˜• ์ŠคํŠธ๋ฆผ

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

reduce ๋ฉ”์„œ๋“œ๋กœ ์ŠคํŠธ๋ฆผ ์š”์†Œ์˜ ํ•ฉ์„ ๊ตฌํ•˜๋Š” ์˜ˆ์ œ์ด๋‹ค.

์ด ์ฝ”๋“œ์—๋Š” ๋ฐ•์‹ฑ ๋น„์šฉ์ด ์ˆจ์–ด์žˆ๋‹ค.

๋‚ด๋ถ€์ ์œผ๋กœ ํ•ฉ๊ณ„๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์ „์— Integer ๋ฅผ ๊ธฐ๋ณธํ˜•์œผ๋กœ ์–ธ๋ฐ•์‹ฑํ•ด์•ผ ํ•œ๋‹ค.

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

์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด sum ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์ง€๋งŒ ์ง์ ‘ ํ˜ธ์ถœ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

map ๋ฉ”์„œ๋“œ๋Š” Stream<T> ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ ํ˜•์‹์€ Integer ์ด์ง€๋งŒ ์ธํ„ฐํŽ˜์ด์Šค์—๋Š” sum ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๋‹ค.

๋‹คํ–‰ํžˆ๋„ ์ŠคํŠธ๋ฆผ API ์ˆซ์ž ์ŠคํŠธ๋ฆผ์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ณธํ˜• ํŠนํ™” ์ŠคํŠธ๋ฆผ์„ ์ œ๊ณตํ•œ๋‹ค.

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

์ž๋ฐ” 8์—์„œ๋Š” ์„ธ ๊ฐ€์ง€ ๊ธฐ๋ณธํ˜• ํŠนํ™” ์ŠคํŠธ๋ฆผ์„ ์ œ๊ณตํ•œ๋‹ค.

  • IntStream
  • DoubleStream
  • LongStream

ํŠนํ™” ์ŠคํŠธ๋ฆผ์€ ์˜ค์ง ๋ฐ•์‹ฑ ๊ณผ์ •์—์„œ ์ผ์–ด๋‚˜๋Š” ํšจ์œจ์„ฑ๊ณผ ๊ด€๋ จ ์žˆ์œผ๋ฉฐ ์ŠคํŠธ๋ฆผ์— ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.

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

์ŠคํŠธ๋ฆผ์„ ํŠนํ™” ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ๋Š” mapToInt mapToDouble mapToLong ์„ธ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.

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

mapToInt ๋Š” ๋ชจ๋“  Integer ํ˜•์‹ ์นผ๋กœ๋ฆฌ๋ฅผ ์ถ”์ถœํ•œ ๋‹ค์Œ์— IntStream ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ IntStream ์—์„œ ์ œ๊ณตํ•˜๋Š” sum ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์นผ๋กœ๋ฆฌ ํ•ฉ๊ณ„๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค.

์ŠคํŠธ๋ฆผ์ด ๋น„์–ด์žˆ๋‹ค๋ฉด ๊ธฐ๋ณธ๊ฐ’ 0์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

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

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

๊ธฐ๋ณธ๊ฐ’ : OptionalInt

ํ•ฉ๊ณ„์—์„œ๋Š” 0์ด๋ผ๋Š” ๊ธฐ๋ณธ๊ฐ’์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ

IntStream ์—์„œ ์ตœ๋Œ“๊ฐ’์„ ์ฐพ์„ ๋•Œ๋Š” 0์ด๋ผ๋Š” ๊ธฐ๋ณธ๊ฐ’ ๋•Œ๋ฌธ์— ์ž˜๋ชป๋œ ๊ฒฐ๊ณผ๊ฐ€ ๋„์ถœ๋  ์ˆ˜ ์žˆ๋‹ค.

์ŠคํŠธ๋ฆผ์— ์š”์†Œ๊ฐ€ ์—†๋Š” ์ƒํ™ฉ์„ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ๋„๋ก Optioanl ์ฐธ์กฐ ํ˜•์‹์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
OptionalInt maxCalories = menu.stream()
															.mapToInt(Dish::getCalories)
															.max();

OptionalInt OptionalDouble OptionalLong ์„ธ ๊ฐ€์ง€ ๊ธฐ๋ณธํ˜• ํŠนํ™” ์ŠคํŠธ๋ฆผ ๋ฒ„์ „์„ ์ œ๊ณตํ•œ๋‹ค.

1
int max = maxCalories.orElse(1); // ๊ฐ’์ด ์—†์„ ๋•Œ ๊ธฐ๋ณธ ์ตœ๋Œ“๊ฐ’์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ • 

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

ํŠน์ • ๋ฒ”์œ„์˜ ์ˆซ์ž๋ฅผ ์ด์šฉํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์ž์ฃผ ๋ฐœ์ƒํ•œ๋‹ค.

์ž๋ฐ” 8์˜ IntStream ๊ณผ LongStream ์—์„œ๋Š” range ์™€ rangeClosed ๋ผ๋Š” ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

range ๋Š” ์‹œ์ž‘๊ฐ’๊ณผ ์ข…๋ฃŒ๊ฐ’์ด ๊ฒฐ๊ณผ์— ํฌํ•จ๋˜์ง€ ์•Š๋Š” ๋ฐ˜๋ฉด

rangeClosed ๋Š” ์‹œ์ž‘๊ฐ’๊ณผ ์ข…๋ฃŒ๊ฐ’์ด ๊ฒฐ๊ณผ์— ํฌํ•จ๋œ๋‹ค๋Š” ์ ์ด ๋‹ค๋ฅด๋‹ค.

1
2
3
IntStream evenNumbers = IntStream.rangeClosed(1, 100) // [1, 100] ๋ฒ”์œ„
																 .filter(n -> n % 2 == 0); // ์ง์ˆ˜ ์ŠคํŠธ๋ฆผ
System.out.println(evenNumbers.count());

์ด ์ฝ”๋“œ๋Š” 1๋ถ€ํ„ฐ 100๊นŒ์ง€์˜ ์ˆซ์ž๋ฅผ ๋งŒ๋“ค๊ณ  ์ง์ˆ˜๋งŒ ํ•„ํ„ฐ๋งํ•œ ํ›„ ์ง์ˆ˜ 50๊ฐœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

์„ธ ์ˆ˜ ํ‘œํ˜„ํ•˜๊ธฐ

์„ธ ์š”์†Œ๋ฅผ ๊ฐ–๋Š” int ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด (3,4,5) ๋ฅผ new int[]{3, 4, 5} ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ข‹์€ ํ•„ํ„ฐ๋ง ์กฐํ•ฉ

ํ”ผ๋ผ๊ณ ๋ผ์Šค ๊ณต์‹์„ ๋งŒ์กฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•œ๋‹ค.

1
Math.sqrt(a*a + b*b) % 1 == 0
1
filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)

์ง‘ํ•ฉ ์ƒ์„ฑ

์ด์ œ ๋งˆ์ง€๋ง‰ ์„ธ ๋ฒˆ์งธ ์ˆ˜๋ฅผ ์ฐพ์•„์•ผ ํ•œ๋‹ค.

map ์„ ์‚ฌ์šฉํ•ด์„œ ๊ฐ ์š”์†Œ๋ฅผ ํ”ผํƒ€๊ณ ๋ผ์Šค ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
stream.filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
			**.map(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)});**

b๊ฐ’ ์ƒ์„ฑ

Stream.rangeClosed ๋กœ ์ฃผ์–ด์ง„ ๋ฒ”์œ„์˜ ์ˆ˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
**IntStream.rangeClosed(1, 100)**
				 .filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
				 .**boxed()**
				 ****.map(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)});

๊ฐœ์ฒด๊ฐ’ ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” IntStream ์˜ mapToObj ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์žฌ๊ตฌํ˜„ ํ•œ๋‹ค.

1
2
3
IntStream.rangeClosed(1, 100)
****				 .filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
				 **.mapToObj**(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)});

a๊ฐ’ ์ƒ์„ฑ

๋งˆ์ง€๋ง‰์œผ๋กœ a๊ฐ’์„ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์™„์„ฑํ•œ๋‹ค.

1
2
3
4
5
6
7
Stream<int[]> pythagoreanTriples =
		IntStream.rangeClosed(1, 100).boxed()
						 .flatMap(a ->
								 IntStream.rangeClosed(a, 100)
													.filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
													.mapToObj(b -> new int[]{a, b, (int)Math.sqrt(a*a+b*b)})
						 );

์ฝ”๋“œ ์‹คํ–‰

limit ์„ ์ด์šฉํ•ด์„œ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์„ธ ์ˆ˜๋ฅผ ํฌํ•จํ•˜๋Š” ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค ๊ฒƒ์ธ์ง€๋งŒ ๊ฒฐ์ •ํ•˜๋ฉด ๋œ๋‹ค.

1
2
3
pythagoreamTriples.limit(5)
									.forEach(t -> 
											System.out.println(t[0] + ", " + t[1] + ", " + t[2]));

๊ฐœ์„ ํ•  ์  ?

ํ˜„์žฌ ์ฝ”๋“œ์—์„œ๋Š” ์ œ๊ณฑ๊ทผ์„ ๋‘ ๋ฒˆ ๊ณ„์‚ฐํ•œ๋‹ค.

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

1
2
3
4
5
6
Stream<double[]> pythagoreanTriples2 =
		IntStream.rangeClosed(1, 100).boxed()
						 .flatMap(a -> IntStream.rangeClosed(a, 100)
						 .mapToObj(
								 b -> new double[]{a, b, Math.sqrt(a*a + b*b)}) // ๋งŒ๋“ค์–ด์ง„ ์„ธ ์ˆ˜
						 .filter(t -> t[2] % 1 == 0); // ์„ธ ์ˆ˜์˜ ์„ธ ๋ฒˆ์งธ ์š”์†Œ๋Š” ๋ฐ˜๋“œ์‹œ ์ •์ˆ˜์—ฌ์•ผ ํ•œ๋‹ค.

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

์ผ๋ จ์˜ ๊ฐ’, ๋ฐฐ์—ด, ํŒŒ์ผ, ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

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

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

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

๋‹ค์Œ์ฒ˜๋Ÿผ empty ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ŠคํŠธ๋ฆผ์„ ๋น„์šธ ์ˆ˜ ์žˆ๋‹ค.

1
Stream<String> emptyStream = Stream.empty();

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

์ž๋ฐ” 9์—์„œ๋Š” null ์ด ๋  ์ˆ˜ ์žˆ๋Š” ๊ฐœ์ฒด๋ฅผ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด System.getProperty ๋Š” ํ‚ค์— ๋Œ€์‘๋˜๋Š” ์†์„ฑ์ด ์—†์œผ๋ฉด null ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ด๋Ÿฐ ๋ฉ”์„œ๋“œ๋ฅผ ์ŠคํŠธ๋ฆผ์— ํ™œ์šฉํ•˜๋ ค๋ฉด ๋‹ค์Œ์ฒ˜๋Ÿผ null ์„ ๋ช…์‹œ์ ์œผ๋กœ ํ™•์ธํ•ด์•ผ ํ–ˆ๋‹ค.

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

Stream.ofNullable ์„ ์ด์šฉํ•ด ๋‹ค์Œ์ฒ˜๋Ÿผ ๊ตฌํ˜„ ๊ฐ€๋Šฅํ•˜๋‹ค.

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

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

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

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

[Arrays.stream](http://Arrays.stream) ์„ ์ด์šฉํ•ด์„œ ๋ฐฐ์—ด์„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

1
2
int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum(); // ํ•ฉ๊ณ„๋Š” 41

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

ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋“ฑ์˜ I/O ์—ฐ์‚ฐ์— ์‚ฌ์šฉํ•˜๋Š” ์ž๋ฐ”์˜ NIO API๋„ ์ŠคํŠธ๋ฆผ API์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
long uniqueWords = 0;
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) {
	// ํŒŒ์ผ์„ ์—ด๋‹ค๊ฐ€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ฒ˜๋ฆฌํ•œ๋‹ค.
}

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

ํ•จ์ˆ˜์—์„œ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋‘ ์ •์  ๋ฉ”์„œ๋“œ Stream.iterate ์™€ Stream.generate ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

์ด ์ŠคํŠธ๋ฆผ์€ ์š”์ฒญํ•  ๋•Œ๋งˆ๋‹ค ์ฃผ์–ด์ง„ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ’์„ ๋งŒ๋“ ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฌด์ œํ•œ์œผ๋กœ ๊ฐ’์„ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ณดํ†ต ๋ฌดํ•œํ•œ ๊ฐ’์„ ์ถœ๋ ฅํ•˜์ง€ ์•Š๋„๋ก limit(n) ํ•จ์ˆ˜๋ฅผ ์—ฐ๊ฒฐํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

iterate ๋ฉ”์„œ๋“œ

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

iterate ๋ฉ”์„œ๋“œ๋Š” ์ดˆ๊นƒ๊ฐ’๊ณผ ๋žŒ๋‹ค๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์•„์„œ ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋Š์ž„์—†์ด ์ƒ์‚ฐํ•  ์ˆ˜ ์žˆ๋”ฐ.

์˜ˆ์ œ์—์„œ๋Š” ๋žŒ๋‹ค๋กœ ์ธํ•ด ์ด์ „ ๊ฒฐ๊ณผ์— 2๋ฅผ ๋”ํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ฆ‰ ์ง์ˆ˜ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•œ๋‹ค.

iterate ๋Š” ์š”์ฒญํ•  ๋•Œ ๋งˆ๋‹ค ๊ฐ’์„ ์ƒ์‚ฐํ•˜๊ณ  ๋์ด ์—†์œผ๋ฏ€๋กœ ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ ๋‹ค.

์ด๋Ÿฌํ•œ ์ŠคํŠธ๋ฆผ์„ ์–ธ๋ฐ”์šด๋“œ ์ŠคํŠธ๋ฆผ์ด๋ผ๊ณ  ํ‘œํ˜„ํ•œ๋‹ค.

๋ฐ”๋กœ ์ด๋Ÿฐ ํŠน์ง•์ด ์ŠคํŠธ๋ฆผ๊ณผ ์ปฌ๋ ‰์…˜์˜ ํฐ ์ฐจ์ด์ ์ด๋‹ค.

์ž๋ฐ” 9์˜ iterate ๋ฉ”์„œ๋“œ๋Š” ํ”„๋ ˆ๋””์ผ€์ดํŠธ๋ฅผ ์ง€์›ํ•œ๋‹ค.

์ด ์ฝ”๋“œ๋Š” 0์—์„œ ์‹œ์ž‘ํ•ด์„œ 100๋ณด๋‹ค ํฌ๋ฉด ์ˆซ์ž ์ƒ์„ฑ์„ ์ค‘๋‹จํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

1
2
3
// 0์—์„œ ์‹œ์ž‘ํ•ด์„œ 100๋ณด๋‹ค ํฌ๋ฉด ์ˆซ์ž ์ƒ์„ฑ ์ค‘๋‹จ
IntStream.iterate(0, n -> n < 100, n -> n + 4)
				 .forEach(System.out::println)

๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ํ”„๋ ˆ๋””์ผ€์ดํŠธ๋ฅผ ๋ฐ›์•„ ์–ธ์ œ๊นŒ์ง€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ธ์ง€ ๊ธฐ์ค€์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

filter ๋™์ž‘์œผ๋กœ๋„ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์„๊นŒ?

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

๊ทธ๋ ‡์ง€ ์•Š๋‹ค.

filter ๋ฉ”์„œ๋“œ๋Š” ์–ธ์ œ ์ด ์ž‘์—…์„ ์ค‘๋‹จํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.

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

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

generate ๋ฉ”์„œ๋“œ

generate ๋ฉ”์„œ๋“œ๋„ ์š”๊ตฌํ•  ๋•Œ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ƒ์‚ฐ๋œ ๊ฐ ๊ฐ’์„ ์—ฐ์†์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜์ง€ ์•Š๋Š”๋‹ค.

generate ๋Š” Supplier<T> ๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์•„์„œ ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ƒ์‚ฐํ•œ๋‹ค.

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

์ด ์ฝ”๋“œ๋Š” 0์—์„œ 1์‚ฌ์ด์˜ ์ž„์˜์˜ Double ํ˜• ์ˆซ์ž ๋‹ค์„ฏ ๊ฐœ๋ฅผ ๋งŒ๋“ ๋‹ค.

1
2
3
4
5
0.9410810294106129
0.6586270755634592
0.9592859117266873
0.13743396659487006
0.3942776037651241

์ด๋ฒˆ์—๋„ ๋ช…์‹œ์ ์œผ๋กœ limit ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ŠคํŠธ๋ฆผ์˜ ํฌ๊ธฐ๋ฅผ ํ•œ์ •ํ–ˆ๋‹ค.

limit ์ด ์—†๋‹ค๋ฉด ์ŠคํŠธ๋ฆผ์€ ์–ธ๋ฐ”์šด๋“œ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.

generate๋Š” ์–ธ์ œ ์‚ฌ์šฉํ• ๊นŒ?

generate๋Š” ์ƒํƒœ๊ฐ€ ์—†๋Š” ๋ฉ”์„œ๋“œ, ์ฆ‰ ๋‚˜์ค‘์— ๊ณ„์‚ฐํ•  ์–ด๋–ค ๊ฐ’๋„ ์ €์žฅํ•˜์ง€ ์•Š๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

๋ณ‘๋ ฌ ์ฝ”๋“œ์—์„œ๋Š” ๋ฐœํ–‰์ž(Supplier)์— ์ƒํƒœ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ์ „ํ•˜์ง€ ์•Š๋‹ค.

IntStream์„ ์ด์šฉํ•˜๋ฉด ๋ฐ•์‹ฑ ์—ฐ์‚ฐ ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

IntStream์˜ generate ๋ฉ”์„œ๋“œ๋Š” Supplier<T> ๋Œ€์‹ ์— IntSupplier๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.

1
IntStream ones = IntStream.generate(() -> 1);

๋žŒ๋‹ค๋กœ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ”๋กœ ๋งŒ๋“ค์–ด ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

1
2
3
4
5
IntStream twos = IntStream.generate(new IntSupplier(){
		public int getAsInt() {
				return 2;
		}
});

generate ๋ฉ”์„œ๋“œ๋Š” ์ฃผ์–ด์ง„ Supplier ๋ฅผ ํ™œ์šฉํ•ด์„œ 2๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” getAsInt ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ˜ธ์ถœํ•  ๊ฒƒ์ด๋‹ค.

์ต๋ช… ํด๋ž˜์Šค์™€ ๋žŒ๋‹ค๋Š” ๋น„์Šทํ•œ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ์ต๋ช… ํด๋ž˜์Šค์—์„œ๋Š” ๋ฉ”์„œ๋“œ์˜ ์—ฐ์‚ฐ์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ๋‹ค๋ฅด๋‹ค.

๋ฐ”๋กœ ๋ถ€์ž‘์šฉ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ๋ณด์—ฌ์ค€๋‹ค.

ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด ์ž‘์—…์—์„œ ๊ธฐ์กด ์ˆ˜์—ด ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  getAsInt ๋กœ ๋‹ค์Œ ์š”์†Œ๋ฅผ ๊ฒŒ์‚ฐํ•˜๋„๋ก IntSupplier๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ๋˜ ๋‹ค์Œ์— ํ˜ธ์ถœ๋  ๋•Œ๋Š” IntSupplier ์˜ ์ƒํƒœ๋ฅผ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
// ํ”ผ๋ณด๋‚˜์น˜ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก IntSupplier ๊ตฌํ˜„
IntSupplier fib = 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 ์ธ์Šคํ„ด์Šค๋Š” ๊ฐ€๋ณ€ ์ƒํƒœ ๊ฐ์ฒด์ด๋‹ค.

getAsInt ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๊ฐ์ฒด ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋ฉฐ ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ƒ์‚ฐํ•œ๋‹ค.

iterate๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ๋Š” ๊ธฐ์กด ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ƒ์„ฑํ•˜๋Š” ์ˆœ์ˆ˜ํ•œ ๋ถˆํŽธ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ–ˆ๋‹ค.

์ŠคํŠธ๋ฆผ์„ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ ์˜ฌ๋ฐ”๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์–ป์œผ๋ ค๋ฉด ๋ถˆ๋ณ€ ์ƒํƒœ ๊ธฐ๋ฒ•์„ ๊ณ ์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค.

๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์—์„œ๋Š” limit ์„ ์ด์šฉํ•ด์„œ ๋ช…์‹œ์ ์œผ๋กœ ์ŠคํŠธ๋ฆผ ํฌ๊ธฐ๋ฅผ ์ œํ•œํ•ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์•„๋ฌด ๊ฒฐ๊ณผ๋„ ๊ณ„์‚ฐ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฌดํ•œ์ ์œผ๋กœ ๊ณ„์‚ฐ์ด ๋ฐ˜๋ณต๋˜๋ฏ€๋กœ ์ •๋ ฌํ•˜๊ฑฐ๋‚˜ ๋ฆฌ๋“€์Šค ํ•  ์ˆ˜ ์—†๋‹ค.

This post is licensed under CC BY 4.0 by the author.