STREAM2

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

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

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

ํ•˜์ง€๋งŒ ์œ„ ์ฝ”๋“œ์—์„  ํ•ฉ๊ณ„๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์ „์— Integer๋ฅผ ๊ธฐ๋ณธํ˜•์œผ๋กœ ์–ธ๋ฐ•์‹ฑํ•ด์•ผํ•œ๋‹ค.

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

์ŠคํŠธ๋ฆผ API๋Š” ๋ฐ•์‹ฑ ๋น„์šฉ์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋„๋ก IntStream, DoubleStream, LoingStream์„ ์ œ๊ณตํ•œ๋‹ค.

๊ฐ๊ฐ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋Š” sum, max์™€ ๊ฐ™์€ ์ˆซ์ž ๊ด€๋ จ ๋ฆฌ๋“€์‹ฑ ์—ฐ์‚ฐ ์ˆ˜ํ–‰ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, ๋‹ค์‹œ ๊ฐ์ฒด ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณต์›ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•œ๋‹ค.

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

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

mapToInt ๋ฉ”์„œ๋“œ๋Š” ๊ฐ ์š”๋ฆฌ์—์„œ ๋ชจ๋“  ์นผ๋กœ๋ฆฌ(Intergerํ˜•์‹)๋ฅผ ์ถ”์ถœํ•œ ๋‹ค์Œ์— IntStream์„(Stream<Integer>๊ฐ€ ์•„๋‹˜) ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ŠคํŠธ๋ฆผ์ด ๋น„์–ด์žˆ์œผ๋ฉด sum์€ ๊ธฐ๋ณธ๊ฐ’ 0์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

boxed ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ํŠนํ™” ์ŠคํŠธ๋ฆผ์„ ์ผ๋ฐ˜ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();

๊ธฐ๋ณธ๊ฐ’: OptionalInt

Optional์„ Integer, String ๋“ฑ์˜ ์ฐธ์กฐ ํ˜•์‹์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐํ™”ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, OptionalInt, OptionalDouble, OptionalLoing ์„ธ ๊ฐ€์ง€ ๊ธฐ๋ณธํ˜• ํŠนํ™” ์ŠคํŠธ๋ฆผ ๋ฒ„์ „๋„ ์ œ๊ณตํ•œ๋‹ค.

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

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

IntStream๊ณผ LongStream์—์„œ๋Š” range์™€ rangeClosed๋ผ๋Š” ๋‘ ๊ฐ€์ง€ ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๋‘ ๋ฉ”์„œ๋“œ ๋ชจ๋‘ ์‹œ์ž‘๊ฐ’๊ณผ ์ข…๋ฃŒ๊ฐ’์„ ์ธ์ˆ˜๋กœ ๊ฐ€์ง„๋‹ค.

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

IntStream evenNumbers = IntStream.rangeClosed(1, 100).filter(n -> n % 2 == 0);

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

ํ•œ ๋‹จ๊ณ„์”ฉ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๊ฐ€๋ฉฐ ์ˆซ์ž ์ŠคํŠธ๋ฆผ๊ณผ ์ŠคํŠธ๋ฆผ ์—ฐ์‚ฐ์„ ํ™œ์šฉํ•ด 'ํ”ผํƒ€๊ณ ๋ผ์Šค ์ˆ˜' ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค์–ด๋ณด์ž.

ํ”ผํƒ€๊ณ ๋ผ์Šค ์ˆ˜

a x a + b x b = c x c

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

int ๋ฐฐ์—ด์„ ๋จผ์ € ์ •์˜ํ•˜์ž. ์˜ˆ๋ฅผ ๋“ค์–ด (3,4,5)๋ฅผ new int[] {3, 4, 5}๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

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

ํ”ผํƒ€๊ณ ๋ผ์Šค ์ •์˜๋ฅผ ๋งŒ์กฑํ•˜๋Š” ์ •์ˆ˜ ์กฐํ•ฉ์„ ์ฐพ์•„๋ณด์ž.

a์™€ b ๋‘ ์ˆ˜๊ฐ€ ์žˆ์„๋•Œ c๊ฐ€ ์ •์ˆ˜์ธ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Math.sqrt(a*a + b*b) % 1 == 0;

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

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

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๋กœ b ๊ฐ’์˜ ๋ฒ”์œ„๋ฅผ ์ƒ์„ฑํ•ด๋ณด์ž.

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

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

IntStream์˜ map์€ ์ŠคํŠธ๋ฆผ์˜ ๊ฐ ์š”์†Œ๋กœ int๊ฐ€ ๋ฐ˜ํ™˜๋  ๊ฒƒ์„ ๊ธฐ๋Œ€ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ boxed ๋ฉ”์„œ๋“œ๋กœ Stream<Integer>ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•œ ํ›„์— map ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, IntStream์˜ mapToObj ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

a๊ฐ’ ์ƒ์„ฑ

๋งˆ์ง€๋ง‰์œผ๋กœ a๊ฐ’์„ ์ƒ์„ฑํ•œ๋‹ค.

Stream<int[]> pythagoreanTriples = IntStream.rangeClose(1, 100).boxed()
   .flatMap(a -> IntStream.rangeClose(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)})

์ŠคํŠธ๋ฆผ a์˜ ๊ฐ’์„ ๋งคํ•‘ํ•˜๋ฉด ์ŠคํŠธ๋ฆผ์˜ ์ŠคํŠธ๋ฆผ์ด ๋งŒ๋“ค์–ด์ง€๋ฏ€๋กœ flatMap ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ํ‰์ค€ํ™”ํ•œ๋‹ค.

์ค‘๋ณต๋œ ์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ์œ„ํ•ด b ๊ฐ’์˜ ๋ฒ”์œ„๋Š” (a, 100)์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

๊ฐœ์„ ํ•  ์ ?

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

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

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

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

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

Stream<String> stream = Stream.of("Modern", "Java", "In", "Action");

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

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

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

ofNullable ๋ฉ”์„œ๋“œ๋กœ null์ด ๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ํฌํ•จํ•˜๋Š” ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

์ด ํŒจํ„ด์€ flatMap๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•˜๋‹ค.

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

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 ํŒŒ์ผ๋กœ ์ŠคํŠธ๋ฆผ ๋งŒ๋“ค๊ธฐ

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

Files.lines๋กœ ํŒŒ์ผ์˜ ๊ฐ ํ–‰ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ŠคํŠธ๋ฆผ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

Stream ์ธํ„ฐํŽ˜์ด์Šค๋Š” AutoCloseable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋ฏ€๋กœ, try ๋ธ”๋ก ๋‚ด์˜ ์ž์›์€ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌ๋œ๋‹ค.

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๋ฅผ ์ด์šฉํ•ด์„œ ํ•จ์ˆ˜์—์„œ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๋‘ ์—ฐ์‚ฐ์„ ์ด์šฉํ•˜๋ฉด ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ, ์ฆ‰ ๊ณ ์ •๋œ ์ปฌ๋ ‰์…˜์—์„œ ๊ณ ์ •๋œ ํฌ๊ธฐ๋กœ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค์—ˆ๋˜ ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ ํฌ๊ธฐ๊ฐ€ ๊ณ ์ •๋˜์ง€ ์•Š์€ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

iterate ๋ฉ”์„œ๋“œ

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

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

์˜ˆ์ œ์—์„œ๋Š” ๋žŒ๋‹ค n -> n+2, ์ฆ‰ ์ด์ „ ๊ฒฐ๊ณผ์— 2๋ฅผ ๋”ํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

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

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

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

filter๋กœ๋„ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, filter ๋ฉ”์„œ๋“œ๋Š” ์–ธ์ œ ์ด ์ž‘์—…์„ ์ค‘๋‹จํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.

์ด๋Ÿด ๋•Œ์—๋Š” talkWhile ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

// ๋ถˆ๊ฐ€
IntStream.iterate(0, n -> n + 4)
   .filter(n -> n < 100)
   .forEach(System.out::println);
   
// ๊ฐ€๋Šฅ
IntStream.iterate(0, n -> n + 4)
   .talkWhile(n -> n < 100)
   .forEach(System.out::println);

generate ๋ฉ”์„œ๋“œ

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

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

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

Last updated

Was this helpful?