๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๊ฐœ๋ฐœ/Java

[JAVA 8] ์ŠคํŠธ๋ฆผ(Stream)

by 1mj 2022. 1. 15.

Stream

java 8 ์ด์ „์—๋Š” ๋ฐฐ์—ด ๋˜๋Š” ์ปฌ๋ ‰์…˜์„ ์ˆœํšŒํ•˜๊ธฐ ์œ„ํ•ด for ๋˜๋Š” foreach๋ฌธ์„ ๋Œ๋ฉฐ ์š”์†Œ ํ•˜๋‚˜์”ฉ ๊บผ๋‚ด์„œ ๋‹ค๋ฃจ์–ด์•ผ ํ–ˆ๋‹ค.

stream์„ ํ™œ์šฉํ•˜๋ฉด ๋ฐฐ์—ด ๋˜๋Š” ์ปฌ๋ ‰์…˜์— ํ•จ์ˆ˜ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์กฐํ•ฉํ•ด์„œ ํ•„ํ„ฐ๋งํ•˜๊ฑฐ๋‚˜ ๊ฐ€๊ณตํ•˜์—ฌ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋žŒ๋‹ค๋ฅผ ์ด์šฉํ•ด ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ๋‚ด๋ถ€ ๋ฐ˜๋ณต์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ๊ฐ€ ์‰ฝ๋‹ค.

 

  • Stream์€ ์›๋ณธ ๋ฐ์ดํ„ฐ ์ž์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • Stream์€ ์ผํšŒ์šฉ์œผ๋กœ ์žฌ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
  • Stream์€ ๋ฐ˜๋ณต๋ฌธ์„ ๋‚ด๋ถ€์— ์ˆจ๊ธฐ๋Š” ๋‚ด๋ถ€ ๋ฐ˜๋ณต์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

 

Stream ๊ตฌ์กฐ

๊ฐ์ฒด.์ŠคํŠธ๋ฆผ์ƒ์„ฑ().๊ฐ€๊ณต().๊ฒฐ๊ณผ();

์ค‘๊ฐœ ์—ฐ์‚ฐ์ด ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋ฅผ stream์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฐ์†์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ์ƒ์„ฑ : ์ŠคํŠธ๋ฆผ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
  2. ์ค‘๊ฐœ ์—ฐ์‚ฐ(๊ฐ€๊ณตํ•˜๊ธฐ) : filltering, mapping ๋“ฑ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋Š” ์ค‘๊ฐ„ ์ž‘์—…
  3. ์ตœ์ข… ์—ฐ์‚ฐ(๊ฒฐ๊ณผ ๋งŒ๋“ค๊ธฐ) : ์ตœ์ข…์ ์œผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์ž‘์—…

 

์ŠคํŠธ๋ฆผ์€ ๋ฐ์ดํ„ฐ์˜ ํ•„ํ„ฐ๋ง, ๋งคํ•‘, ์ •๋ ฌ, ๊ทธ๋ฃนํ•‘ ๋“ฑ์˜ ์ค‘๊ฐ„์ฒ˜๋ฆฌ์™€ ํ•ฉ๊ณ„, ํ‰๊ท , ์นด์šดํŒ…, ์ตœ๋Œ“๊ฐ’, ์ตœ์†Ÿ๊ฐ’ ๋“ฑ์˜ ์ตœ์ข…์ฒ˜๋ฆฌ๋ฅผ ํŒŒ์ดํ”„๋ผ์ธ์œผ๋กœ ํ•ด๊ฒฐํ•œ๋‹ค.

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

 

โ‘  Stream ์ƒ์„ฑ

์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์†Œ์Šค๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

๋ฐ์ดํ„ฐ ์†Œ์Šค ์„ค๋ช…
์ปฌ๋ ‰์…˜ ์ปฌ๋ ‰์…˜์˜ ์กฐ์ƒ์ธ Collection ์ธํ„ฐํŽ˜์ด์Šค์— stream() ๋ฉ”์†Œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์Œ
parallelStream() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Œ
๋ฐฐ์—ด Arrays ํด๋ž˜์Šค์— stream() ๋ฉ”์†Œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์Œ
๊ธฐ๋ณธ ํƒ€์ž…์ธ int, long, double ํ˜•์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์ŠคํŠธ๋ฆผ์€ java.util.stream ํŒจํ‚ค์ง€์˜ IntStream, LongStream, DoubleStream์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ œ๊ณต๋จ
๊ฐ€๋ณ€ ๋งค๊ฐœ๋ณ€์ˆ˜ Stream ํด๋ž˜์Šค์˜ of() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ€๋ณ€ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Œ
์ง€์ •๋œ ๋ฒ”์œ„์˜ ์—ฐ์†๋œ ์ •์ˆ˜ IntStream์ด๋‚˜ LongStream ์ธํ„ฐํŽ˜์ด์Šค์—๋Š” range()์™€ rangeClosed() ๋ฉ”์†Œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์Œ
ํŠน์ • ํƒ€์ž…์˜ ๋‚œ์ˆ˜๋“ค Random ํด๋ž˜์Šค์—๋Š” ints(), longs(), doubles()์™€ ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์Œ
๋žŒ๋‹ค ํ‘œํ˜„์‹ Stream ํด๋ž˜์Šค์— iterate()์™€ generate() ๋ฉ”์†Œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์Œ
ํŒŒ์ผ java.nio.file.Files ํด๋ž˜์Šค์—๋Š” lines() ๋ฉ”์†Œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์Œ
๋นˆ ์ŠคํŠธ๋ฆผ ์•„๋ฌด ์š”์†Œ๋„ ์—†๋Š” ์ŠคํŠธ๋ฆผ์€ Stream ํด๋ž˜์Šค์˜ empty() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Œ
// ์ŠคํŠธ๋ฆผ ์ƒ์„ฑ(์ŠคํŠธ๋ฆผ ๋นŒ๋”)
Stream<String> builderStream = Stream.<String>builder().add("A").add("B").add("C").build(); // A, B, C

// ์ปฌ๋ ‰์…˜
List<String> list1 = Arrays.asList("A", "B", "C");

Stream<String> stream1 = list1.stream();
stream1.forEach(System.out::println);	// A, B, C

// ๋ฐฐ์—ด
String[] arr1 = new String[]{"A", "B", "C"};

Stream<String> stream2 = Arrays.stream(arr1);
stream2.forEach(System.out::println);	// A, B, C

Stream<String> stream3 = Arrays.stream(arr1, 1, 3);
stream3.forEach(System.out::println);	// 1~2 ์š”์†Œ A, B

// ๊ฐ€๋ณ€ ๋งค๊ฐœ๋ณ€์ˆ˜
Stream<Integer> stream4 = Stream.of(1, 2, 3, 4, 5);
stream4.forEach(System.out::println);	// 1, 2, 3, 4, 5

// ์ง€์ •๋œ ๋ฒ”์œ„์˜ ์—ฐ์†๋œ ์ •์ˆ˜
IntStream intStream1 = IntStream.range(1, 5);
intStream1.forEach(x -> System.out.print(x + " "));	// 1 2 3 4

// ํŠน์ • ํƒ€์ž…์˜ ๋‚œ์ˆ˜
IntStream intStream2 = new Random().ints(4);
intStream2.forEach(System.out::println);	// random int 4๊ฐœ

// ๋žŒ๋‹ค ํ‘œํ˜„์‹
// iterate(): ์ดˆ๊ธฐ ๊ฐ’๊ณผ ํ•ด๋‹น ๊ฐ’์„ ๋‹ค๋ฃจ๋Š” ๋žŒ๋‹ค๋ฅผ ์ด์šฉํ•ด ์ŠคํŠธ๋ฆผ์— ๋“ค์–ด๊ฐˆ ์š”์†Œ๋ฅผ ๋งŒ๋“ฆ
Stream<Integer> iteratedStream = Stream.iterate(1, n -> n + 1).limit(5); // [1, 2, 3, 4, 5]
// generate(): Supplier<T>์— ํ•ด๋‹นํ•˜๋Š” ๋žŒ๋‹ค๋กœ ๊ฐ’์„ ๋„ฃ์„ ์ˆ˜ ์žˆ์Œ
Stream<String> generatedStream = Stream.generate(() -> "new item").limit(5); // [el, el, el, el, el]

// ํŒŒ์ผ
Stream<String> lineStream = Files.lines(Paths.get("fileName.txt"), Charset.forName("UTF-8"));

// ๋นˆ ์ŠคํŠธ๋ฆผ
Stream<Object> stream5 = Stream.empty();
System.out.println(stream5.count()); // 0

// ๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ
Stream<String> parallelStream = Arrays.asList(new String[]{"A", "B", "C"}).parallelStream();
boolean isParallel = parallelStream.isParallel();	// ๋ณ‘๋ ฌ ์—ฌ๋ถ€ ํ™•์ธ
parallelStream.map(x -> x + "-").anyMatch(y -> y == "A-");	// ๋ณ‘๋ ฌ๋กœ ์ˆ˜ํ–‰

 

โ‘ก ์ค‘๊ฐœ ์—ฐ์‚ฐ

์—ฐ์‚ฐ ๋ฉ”์†Œ๋“œ
ํ•„ํ„ฐ๋ง filter(), distinct()
๋ณ€ํ™˜ map(), flatMap()
์ œํ•œ limit(), skip()
์ •๋ ฌ sorted()
์—ฐ์‚ฐ ๊ฒฐ๊ณผ ํ™•์ธ peek()
// filter(): ์ธ์ž๋กœ ๋ฐ›๋Š” Predicate๋Š” boolean์„ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋“ค์–ด๊ฐ
List<String> list1 = Arrays.asList("Anna", "Erica", "Justin");
Stream<String> stream1 = list1.stream();
stream1.filter(n -> n.contains("a")).forEach(e -> System.out.print(e + " ");	// Anna Erica

// distinct()
IntStream stream2 = IntStream.of(1, 2, 3, 3);
stream2.distinct().forEach(e -> System.out.print(e + " "));	// 1 2 3

// map()
Stream<String> stream3 = Stream.of("A", "B", "C");
stream3.map(String::toLowerCase).forEach(System.out::println));	// a, b, c

// flatMap(): ์ค‘์ฒฉ ๊ตฌ์กฐ๋ฅผ ํ•œ ๋‹จ๊ณ„ ์ œ๊ฑฐํ•˜๊ณ  ๋‹จ์ผ ์ปฌ๋ ‰์…˜์œผ๋กœ ๋งŒ๋“ค์–ด์คŒ
List<List<String>> list2 = Arrays.asList(Arrays.asList("A"), Arrays.asList("B"));
System.out.println(list2.stream().flatMap(Collection::stream).collect(Collectors.toList()));	// [A, B]

// skip(): ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ถ€ํ„ฐ ์ „๋‹ฌ๋œ ๊ฐœ์ˆ˜๋งŒํผ์„ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ์š”์†Œ๋งŒ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ์ƒˆ๋กœ์šด ์ŠคํŠธ๋ฆผ
// limit(): ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ถ€ํ„ฐ ์ „๋‹ฌ๋œ ๊ฐœ์ˆ˜๋งŒํผ์˜ ์š”์†Œ๋งŒ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ์ƒˆ๋กœ์šด ์ŠคํŠธ๋ฆผ
IntStream stream4 = IntStream.range(1, 10);	// 1, 2, 3, 4, 5, 6, 7, 8, 9
stream4.skip(3).limit(3).forEach(System.out::println);	// 4, 5, 6

// sorted()
// boxed(): int, long, double ์š”์†Œ๋ฅผ Integer, Long, Double ์š”์†Œ๋กœ ๋ฐ•์‹ฑ
IntStream.of(1, 3, 5, 4, 2).sorted().boxed().collect(Collectors.toList));	// [1, 2, 3, 4, 5]
IntStream.of(1, 3, 5, 4, 2).sorted(Comparator.reverseOrder()).boxed().collect(Collectors.toList));	// [5, 4, 3, 2, 1]

// peek(): ์ŠคํŠธ๋ฆผ ๋‚ด ์š”์†Œ๋“ค ๊ฐ๊ฐ์— ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰
IntStream.of(1, 2, 3, 5, 4).peek(System.out::println).count();	// 1, 2, 3, 5, 4(๊ฒฐ๊ณผ๋Š” 5)

 

โ‘ข ์ตœ์ข… ์—ฐ์‚ฐ

์—ฐ์‚ฐ ๋ฉ”์†Œ๋“œ
์ถœ๋ ฅ forEach()
์†Œ๋ชจ reduce()
๊ฒ€์ƒ‰ findFirst(), findAny()
๊ฒ€์‚ฌ anyMatch(), allMatch(), noneMatch()
ํ†ต๊ณ„ count(), min(), max()
์—ฐ์‚ฐ sum(), average()
์ˆ˜์ง‘ collect()
// forEach()
Stream<String> stream1 = Stream.of("A", "B", "C");
stream1.forEach(System.out::println);	// A, B, C

// reduce()
// - identity: ๊ณ„์‚ฐ์„ ์œ„ํ•œ ์ดˆ๊ธฐ ๊ฐ’
// - accumulator: ๊ฐ ์š”์†Œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณ„์‚ฐ ๋กœ์ง
// - combiner: ๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ์—์„œ ๋‚˜๋ˆ  ๊ณ„์‚ฐํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ•˜๋‚˜๋กœ ํ•ฉ์นจ
Stream<String> stream2 = Stream.of("A", "B", "C");
stream2.reduce(">>>", (a, b) -> a + "-" + b);	// >>>A-B-C

// findFirst(): ๊ฐ€์žฅ ์•ž์— ์žˆ๋Š” ์š”์†Œ ๋ฆฌํ„ด
// findAny(): ๊ฐ€์žฅ ๋จผ์ € ์ฐพ์€ ์š”์†Œ ๋ฆฌํ„ด(๋ณ‘๋ ฌ์ฒ˜๋ฆฌ์—์„œ ์ฐจ์ด๊ฐ€ ์žˆ์Œ)
IntStream stream3 = IntStream.of(1, 2, 3, 5, 4);
System.out.println(stream3.sorted().findFirst().getAsInt());	// 1, ์ •๋ ฌ ํ›„ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ ๋ฆฌํ„ด

// collect()
Stream<String> stream4 = Stream.of("B", "A", "C");
List<String> list = stream4.collect(Collectors.toList());	// ์ŠคํŠธ๋ฆผ์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜, ["B", "A", "C"]

 

์ฐธ๊ณ ์ž๋ฃŒ ๋ฐ ์ถœ์ฒ˜ ๐Ÿ™‡‍โ™‚๏ธ

https://ahndding.tistory.com/23

https://futurecreator.github.io/2018/08/26/java-8-streams/

http://www.tcpschool.com/java/java_stream_creation

https://beomseok95.tistory.com/217

๋Œ“๊ธ€