Java 8 Stream

์•ˆ๋…•ํ•˜์„ธ์š”. ์˜ค๋Š˜์€ Java 8์˜ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ธ Stream์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. Stream์€ ๋ฐฐ์—ด, List๋“ฑ์˜ ์š”์†Œ๋“ค์˜ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” Class๋กœ์จ ๊ธฐ์กด์˜ ๋ฐฐ์—ด์ฒ˜๋ฆฌ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด์ฃผ๋ฉฐ, functional style๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ Optional ๋“ฑ ๋‹ค์–‘ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ด์ค๋‹ˆ๋‹ค.

1. ์š”์†Œ์˜ ์ถœ๋ ฅ : forEach() 2. ์š”์†Œ์˜ ์†Œ๋ชจ : reduce() 3. ์š”์†Œ์˜ ๊ฒ€์ƒ‰ : findFirst(), findAny() 4. ์š”์†Œ์˜ ๊ฒ€์‚ฌ : anyMatch(), allMatch(), noneMatch() 5. ์š”์†Œ์˜ ํ†ต๊ณ„ : count(), min(), max() 6. ์š”์†Œ์˜ ์—ฐ์‚ฐ : sum(), average() 7. ์š”์†Œ์˜ ์ˆ˜์ง‘ : collect()

Stream ์ƒ์„ฑ

Stream์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Stream์„ ์ƒ์„ฑํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. collection ๋˜๋Š” ๋ฐฐ์—ด์„ ์ด์šฉํ•ด์„œ, ๋˜๋Š” ์ž์ฒด์ ์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ๋ง์ด์ฃ .

// from Array
String[] arr = new String[]{"a","b","c"};
Stream<String> stream = Arrays.stream(arr);

// from Collection
List<String> lists = Arrays.asList("a", "b", "c");
Stream<String> stream = lists.stream();

// only Stream Class
Stream<String> stream = Stream.of("a", "b", "c");

Stream์˜ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋”ฉ

Stream API๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ multithreading์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก parallelStream() ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ๋ฐฉ๋ฒ•์€ ์ƒ๋‹นํžˆ ํŽธํ•˜๋‹ˆ๋‹ค๋งŒ ์ด๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ๋‚ด๋ถ€์˜ ๋กœ์ง์„ ์•Œ๊ณ  ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋‚ด์šฉ์€ ์ด ๋งํฌ๋ฅผ ํ™•์ธํ•ด ์ฃผ์‹œ๊ธฐ๋ฐ”๋ž๋‹ˆ๋‹ค. [java8] ๋ณ‘๋ ฌ Stream ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์›ํ•˜์ง€ ์•Š์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

list.parallelStream().forEch(element->doWork(element));

Stream Operations

์ผ๋ฐ˜์ ์œผ๋กœ Stream์€ 2๊ฐ€์ง€ ํ˜•ํƒœ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • intermediate operations

    • return Stream

  • terminal operations

    • return ํŠน์ •ํ•œ type์˜ ๊ฐ’

์ด๋Ÿฐ ํ˜•ํƒœ๋ฅผ ๋„๋ฏ€๋กœ intermediate operations๋ฅผ ํ†ตํ•ด์„œ chainํ˜•ํƒœ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ๋ฅผ ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

List<String> list = Arrays.asList("a", "b", "c");
long count = list.stream() // List<String> to Stream<String>
                .distinct() // return Stream<String>
                .count(); // return long

์œ„๋ฅผ ์„ค๋ช…ํ•˜๋ฉด ์ œ์ผ ๋จผ์ € String ArrayList๋ฅผ Stream์œผ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  distinct() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ค‘๋ณต๋˜๋Š” ๊ฐ’์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ distinct()์— ์˜ํ•ด์„œ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฐ’์€ Stream<String>์ž…๋‹ˆ๋‹ค. ์ฆ‰, ์‚ฌ์šฉ์ž๋Š” ํ•œ๋ฒˆ๋” Stream์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์— count()๋Š” Stream์— ๋“ค์–ด์žˆ๋Š” ์ˆ˜๋ฅผ long type์œผ๋กœ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฐ์‹์œผ๋กœ 2๊ฐ€์ง€์˜ ์ผ์„ 1๊ฐœ์˜ line์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๊ฒŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Stream์„ ์ด์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ผ์„ ํ•œ๋ฒˆ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ๋˜์–ด ๊ฐ„๋žตํ™” ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Stream์˜ ์ง€์›ํ•˜๋Š” ์ œ์–ด

Stream์ด ๊ฐ„๋žตํ™” ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๊ฒŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ด์ œ Stream์—์„œ ์ง€์›ํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ์˜ˆ์ œ๋Š” ์•„๋ž˜์˜ List๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

List<String> list = Arrays.asList("a", "b", "c");

์ˆœํ™˜

Stream API๋Š” for, for-each, while loop๋ฅผ ๋Œ€์‹  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๋ง์ด์ฃ .

list.stream().foreach(element -> ...somthingToDo...);

์‚ฌ์‹ค stream() method์— ์ˆœํ™˜์ด๋ผ๋Š” ๊ฐœ๋…์ด ๋“ค์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์œ„์™€๊ฐ™์ด ์‚ฌ์šฉํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ์ˆœํ™˜์— ๋Œ€ํ•ด์„œ ํŠน์ •๋ถ€์œ„๋ฅผ ํ™•์ธํ•˜๋Š” ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ๋ง์ด์ฃ .

// before
for ( String string : list) {
    if(string.contains("a")) {
        return true;
    }
}

// after
boolean isExist = list.stream().anyMatch(element -> element.contains("a));

ํ•„ํ„ฐ๋ง

filter() ๋ฉ”์„œ๋“œ๋Š” Stream์—์„œ ํŠน์ •ํ•œ ๋‚ด์šฉ๋งŒ ํ†ต๊ณผ์‹œ์ผœ ํŒŒ์ดํ”„๋ผ์ธ์„ ํ˜•์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.

Stream<String> stream = list.stream().filter(e -> element.contains("b"));

์ด๋ ‡๊ฒŒ ๋ฐ˜ํ™˜๋œ stream์˜ ์š”์†Œ๋กœ๋Š” "b" ํ•˜๋‚˜๋งŒ์„ ๋‚จ๊ธฐ๊ณ  ๋ชจ๋‘ filtering๋˜์–ด ์‚ฌ๋ผ์กŒ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ filtering ๋ฉ”์„œ๋“œ๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค ๋•Œ return ๊ฐ’์€ boolean์ด๋ผ๋Š” ๊ทœ์น™์„ ์ง€์ผœ์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

public class Compare {
    public static boolean isB(String string) {
        return string.contains("b");
    }
}

// ์‚ฌ์šฉ
list.stream().filter(Compare::isB); // b

์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ˜น์‹œ lambda์‹์— ๋Œ€ํ•ด์„œ ์ž˜ ๋ชจ๋ฅด์‹œ๊ฒ ๋‹ค๋ฉด ์ €์˜ ์ด์ „ํฌ์Šคํ„ฐ ๋“ค์„ ์ฐธ์กฐํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋งคํ•‘

๋งคํ•‘์€ Stream์˜ ์š”์†Œ๋ฅผ ํŠน์ •ํ•œ ๊ทœ์น™์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ์š”์†Œ๋“ค์„ ๋Œ€๋ฌธ์ž๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

list.stream.map(String::toUpperCase); // A, B, C

์ปค์Šคํ„ฐ๋งˆ์ด์ง•์„ ํ•˜๊ณ ์‹ถ๋‹ค๋ฉด ๋ฉ”์„œ๋“œ๋ฅผ ์ œ์ž‘ํ•  ์‹œ ๊ฐ์ฒด์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ๊ฐ€์ง€๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ค‘๋ณต์ œ๊ฑฐ

reduce() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ค‘๋ณต์œผ๋กœ ์ ์–ด์•ผํ•˜๋Š” ์—ฐ์‚ฐ์„ ํ•œ๋ฒˆ์— ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

list.stream().reduce("1", (a, b) -> a + b); // 1abc

์กฐํ•ฉ

collection() ๋ฉ”์„œ๋“œ๋Š” Stream์„ ๋‹ค์‹œ List, Map ๋“ฑ ๋‹ค์–‘ํ•œ ์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ์•Œ๊ณ  ์žˆ๋Š” Collection, Object๋กœ ๋ณ€ํ™˜ํ•ด ์ค๋‹ˆ๋‹ค.

List<String> resultList = list.stream().map(String::toUpperCase).collect(Collectors.toList());

resultList์—๋Š” stream์—ฐ์‚ฐ์„ ํ†ตํ•ด ๋‚˜์˜จ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋งˆ๋ฌด๋ฆฌ

์ œ ๊ฐœ์ธ์ ์ธ ๊ธฐ์ค€์—์„œ๋Š” Stream์ด์•ผ ๋ง๋กœ Java 8์—์„œ ์ถ”๊ตฌํ•˜๋Š” ๊ฐ„๊ฒฐ์„ฑ์„ ๋‹ฌ์„ฑํ•˜๊ธฐ์œ„ํ•œ ์ตœ๊ณ ์˜ ๋ฌด๊ธฐ๊ฐ€ ์•„๋‹๊นŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. lambda์‹์„ ์ž˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ๊ต‰์žฅํ•˜์ง€๋งŒ ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ Stream๊นŒ์ง€ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์šฐ๋ฆฌ๊ฐ€ ํ•ญ์ƒ ์ง€๋ฃจํ•˜๊ฒŒ ์ˆ˜์‹ญ์ค„ ์”ฉ ์ผ๋˜ ๋‚ด์šฉ์„ 1์ค„, 2์ค„๋กœ ์ค„์—ฌ๋ฒ„๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น ๋ฌธ์„œ๋Š” ์•„๋ž˜ ์ฐธ์กฐ๋ฌธ์„œ๋ฅผ ํ†ตํ•ด ์กฐ๊ธˆ ๋” ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์žฌ๊ฐ€๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.

๋Œ€ํ‘œ์ ์ธ ์ตœ์ข… ์—ฐ์‚ฐ ๋ฉ”์†Œ๋“œ

์ŠคํŠธ๋ฆผ API์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋Œ€ํ‘œ์ ์ธ ์ตœ์ข… ์—ฐ์‚ฐ์„ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ฉ”์†Œ๋“œ

์„ค๋ช…

void forEach(Consumer<? super T> action)

์ŠคํŠธ๋ฆผ์˜ ๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด ํ•ด๋‹น ์š”์†Œ๋ฅผ ์†Œ๋ชจํ•˜์—ฌ ๋ช…์‹œ๋œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•จ.

Optional<T> reduce(BinaryOperator<T> accumulator)

T reduce(T identity, BinaryOperator<T> accumulator)

์ฒ˜์Œ ๋‘ ์š”์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•œ ๋’ค, ๊ทธ ๊ฒฐ๊ณผ์™€ ๋‹ค์Œ ์š”์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ๋˜๋‹ค์‹œ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•จ. ์ด๋Ÿฐ ์‹์œผ๋กœ ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ์†Œ๋ชจํ•˜์—ฌ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•จ.

Optional<T> findFirst()

Optional<T> findAny()

ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์—์„œ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ฅผ ์ฐธ์กฐํ•˜๋Š” Optional ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•จ.

(findAny() ๋ฉ”์†Œ๋“œ๋Š” ๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ์ผ ๋•Œ ์‚ฌ์šฉํ•จ)

boolean anyMatch(Predicate<? super T> predicate)

ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ ์ผ๋ถ€ ์š”์†Œ๊ฐ€ ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•  ๊ฒฝ์šฐ์— true๋ฅผ ๋ฐ˜ํ™˜ํ•จ.

boolean allMatch(Predicate<? super T> predicate)

ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ๊ฐ€ ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•  ๊ฒฝ์šฐ์— true๋ฅผ ๋ฐ˜ํ™˜ํ•จ.

boolean noneMatch(Predicate<? super T> predicate)

ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ๊ฐ€ ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ์— true๋ฅผ ๋ฐ˜ํ™˜ํ•จ.

long count()

ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•จ.

Optional<T> max(Comparator<? super T> comparator)

ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ ์ค‘์—์„œ ๊ฐ€์žฅ ํฐ ๊ฐ’์„ ๊ฐ€์ง€๋Š” ์š”์†Œ๋ฅผ ์ฐธ์กฐํ•˜๋Š” Optional ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•จ.

Optional<T> min(Comparator<? super T> comparator)

ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ ์š”์†Œ ์ค‘์—์„œ ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’์„ ๊ฐ€์ง€๋Š” ์š”์†Œ๋ฅผ ์ฐธ์กฐํ•˜๋Š” Optional ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•จ.

T sum()

ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ์— ๋Œ€ํ•ด ํ•ฉ์„ ๊ตฌํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•จ.

Optional<T> average()

ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋“  ์š”์†Œ์— ๋Œ€ํ•ด ํ‰๊ท ๊ฐ’์„ ๊ตฌํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•จ.

<R,A> R collect(Collector<? super T,A,R> collector)

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

์ฐธ์กฐ

Last updated

Was this helpful?