๐ ์ฃผ์
์ค๋์ Stream API ์์ฒด์ ๋ํด ๋ค๋ฃจ๊ณ ์ ํ๋ค.
โ Stream
Collection Framework
- ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ์กฐ์ํ๋ ๊ตฌ์กฐ์ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ ์๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- List, Set, Map๋ค์ด ํฌํจ๋๊ณ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅ, ๊ฒ์, ์ญ์ ํ๋ ๋ฑ์ ์์ ์ ์ฒ๋ฆฌํ๋ค.
- ์ ๊ตฌ์กฐ๋ค์ ๋ํด์๋ ์ฐจํ ๋ค๋ฅธ ๊ธ๋ก ๋ค๋ฃจ๊ฒ ๋ค.
Stream
- ์ปฌ๋ ์
๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋ฐ์ดํฐ ์์ค์ ์ฐ๊ฒฐ๋์ด ์์๋ ๋ฐ์ดํฐ ํ๋ฆ์ ์ ๊ณตํ๋ค.
- ๋ฐ์ดํฐ๋ฅผ ์ผํ์ฑ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋๊ตฌ.
- ์์: "์คํธ๋ฆผ ์์ ํ์๋ ๋ฐ์ดํฐ๊ฐ ๋ณํํ์ง ์๊ณ ์ง์์ ์ผ๋ก ์กด์ฌํ๋ค"๋ ๋ป์ด๋ค.
- ๋ถ๋ณ์ฑ: ์ฒ๋ฆฌ๋ ๊ฒฐ๊ณผ๋ ์๋ก์ด ๋ฐ์ดํฐ๋ก ์์ฑํ๋ฏ๋ก ์๋ณธ ๋ฐ์ดํฐ๋ ๋ณ๊ฒฝ๋์ง ์๋๋ค.
- ์ง์ฐ ์ฒ๋ฆฌ: ์ค๊ฐ ์ฐ์ฐ๊ณผ ์ต์ข
์ฐ์ฐ
- ์ค๊ฐ ์ฐ์ฐ: ์ต์ข ์ฐ์ฐ์ด ํธ์ถ๋ ๋๊น์ง ์คํ๋์ง ์๊ณ , ๋๊ธฐํ๊ณ ์๋ค๊ฐ ์ต์ข ์ฐ์ฐ์ด ํธ์ถ๋๋ฉด ํ ๋ฒ์ ๋์ํ๋ค. ex) map(), filter(), sorted()...
- ์ต์ข ์ฐ์ฐ: ์คํธ๋ฆผ์ ์๋ชจํด์ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํ๋ค. ์ต์ข ์ฐ์ฐ์ด ํธ์ถ๋๋ฉด ์ด ์คํธ๋ฆผ์ ๋ซํ ์ฌ์ฉํ ์ ์๋ค. -> ๋ฐ์ดํฐ ๋ถ๋ณ์ฑ์ ๋ณด์ฅ.
- ๋ถํ์ํ ์ฐ์ฐ์ ์ค์ฌ ํจ์จ์ ์ผ๋ก ๋์ํ๋ค.
- ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์คํ์ผ์ ์ฌ์ฉํ๋ค.(feat. ๋๋ค ํํ์)
โ Stream์ ์ฅ์
- ๊ฐ๋ ์ฑ์ด ๋๋ค: ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์คํ์ผ์ ๊ฐ๊ฒฐํ๊ณ , ์ต์ํด์ง๋ฉด ์ฝ๊ธฐ๋ ์ฝ๋ค.
- ์ฌ์ด ์ ์ง๋ณด์: ๊ฐ๊ฒฐํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ก์ง์ด๋ผ ์์ ์ด ์ฝ๋ค.
- ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ํตํ ์ฑ๋ฅ ํฅ์:
parallel()
๋๋parallelStream()
์ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ๋ณ๋ ฌํํ ์ ์๋ค.
โ Stream์ ๋จ์
- ๊ฒฝ์ฐ์ ๋ฐ๋ผ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ ์ ์๋ค. ์์ ๋ฐ์ดํฐ์ ์๋ ๋จ์ํ ๋ฐ๋ณต๋ฌธ์ด ๋ซ๋ค.
- ๋๋ฒ๊น ์ด ์ด๋ ต๋ค.
โ ์ฃผ์ Stream API
Stream API๋ ์คํธ๋ฆผ์ ์๋ ์ฐ์ฐ ๊ธฐ๋ฅ์ ๋งํ๋ค. ์ค๊ฐ ์ฐ์ฐ๊ณผ ์ต์ข ์ฐ์ฐ์ผ๋ก ๋๋์ด ์ง๋ค.
- ์ค๊ฐ ์ฐ์ฐ: ๋ฐ์ดํฐ๋ฅผ ๋ณํ๋๊ฑฐ๋ ํํฐ๋งํ๋ ๋ฑ ํ๋์ ์คํธ๋ฆผ์์ ์ฌ๋ฌ ์ฐ์ฐ์ ์ฐ์ํด์ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
- map(), filter(), sorted(), ...
- ์ต์ข
์ฐ์ฐ: ์คํธ๋ฆผ์ ์๋ชจํด์ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํ๋ฏ๋ก ํ๋๋ง ๊ฐ๋ฅํ๋ค.
- forEach(), collect(), reduce(), ...
๐ ๏ธ ์ค๊ฐ ์ฐ์ฐ
filter()
์กฐ๊ฑด์ ๋ง๋ ์์๋ง ์ ํํ๋ค.
List<Integer> numbers = Arrays.asList(1,2,3,4,5);
numbers.stream()
.filter(n -> n >2 )
.forEach(System.out::println);
--------------------------
3
4
5
map()
๋ฐ์ดํฐ๋ฅผ ๋ณํํด์ ์๋ก์ด ํํ๋ก ๋ณํํ๋ค. ์์์์๋ ๋ชจ๋ ๋๋ฌธ์๋ก ๋ฐ๊พผ๋ค.
List<String> names = Arrays.asList("Alice", "Bob", "Christine");
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
--------------------------
ALICE
BOB
CHRISTINE
flatMap()
์ค์ฒฉ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋จ์ผ ํ๋ฉด ๋ฐ์ดํฐ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ๋ค. ์ฆ ์ฌ๋ฌ ๊ณ์ธต์ผ๋ก ์ค์ฒฉ๋ ๋ฐ์ดํฐ๋ฅผ ํ์ด ํ๋ซํ๊ฒ ๋ง๋ ๋ค.
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("A", "B"),
Arrays.asList("C", "D"),
Arrays.asList("E", "F")
);
List<String> flatList = nestedList.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(flatList);
--------------------------
[A, B, C, D, E, F]
map()๊ณผ ๋ค๋ฅธ ์ ์ "์ ๋ ฅ ๊ฐ์์ ์ถ๋ ฅ ๊ฐ์๊ฐ ๋ฐ๋์ ๊ฐ์ง๋ ์๋ค"๋ ์ ์ด๋ค.
map()์ ์์์์ ์ ๋ ฅ ๋ฐ์ดํฐ์ ์ถ๋ ฅ ๋ฐ์ดํฐ์์ ๋ค์ ๋งคํ ๊ด๊ณ๊ฐ ์ฑ๋ฆฝํ๋ค.
Alice -> ALICE
Bob -> BOB
Christine -> CHRISTINE
ํ๋์ ์ ๋ ฅ์ ๋ํด์ ํ๋์ ์ถ๋ ฅ ๊ฒฐ๊ณผ๊ฐ ๋์ค๋ 1:1 ๊ด๊ณ์ด๋ค.
flatMap()์์๋ ๋ค์ ๋งคํ ๊ด๊ณ๊ฐ ์ฑ๋ฆฝํ๋ค.
("A", "B") -> "A", "B"
("C", "D") -> "C", "D"
("E", "F") -> "E", "F"
nestedList๋ ์ค์ฒฉ ๋ฆฌ์คํธ๋ก ๊ฐ๊ฐ์ ์์์ ์ ๊ทผํด๋ ์ฌ๋ฌ ๊ฐ์ผ๋ก ๊ตฌ์ฑ๋ ๋ฆฌ์คํธ์ด๋ค.
nestedList์์์ stream()์ ๋ฆฌ์คํธ ("A" ,"B")๋ผ๋ ํ๋์ ์
๋ ฅ์ ๋ฐ์ "A", "B"๋ก ๋๋๋ค.
์ฆ ์ค์ฒฉ ๊ตฌ์กฐ์๋ nestedList๋ฅผ ์ผ์ฐจ์์ผ๋ก ํ๋ค๊ณ ๋ณผ ์ ์๋ค.
collect()๋ฅผ ์ด์ฉํ๋ค๋ฉด ๋ค์์ฒ๋ผ ํ๋ซํด์ง ๋ฆฌ์คํธ๋ฅผ ๋ฐ๋ก ์ป์ ์ ์๋ค.
List<String> flatList = nestedList.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
sorted()
๊ธฐ์ค์ ๋ฐ๋ผ ์ ๋ ฌํ๋ค. ๊ธฐ์ค์ ๋ฐ๋ก ์ฃผ์ง ์์๋ ์์์ ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ ฌํ๋ค.
numbers.stream()
.sorted()
.forEach(System.out::println);
์ํ๋ ๊ธฐ์ค์ ๋ฃ๊ณ ์ถ๋ค๋ฉด Comparator
๋ Comparator.comparing()
์ ์ด์ฉํ์.
Comparator
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
List<Integer> sorted = numbers.stream()
.sorted((a, b) -> b - a)
.collect(Collectors.toList());
---
\[8, 5, 3, 2, 1\]
Comparator.comparing()
List words = Arrays.asList("appleJuice", "banana", "apricot!", "cherry");
List sorted = words.stream()
.sorted(Comparator.comparing(String::length)) //๊ธธ์ด ๊ธฐ์ค ์ค๋ฆ์ฐจ์
.collect(Collectors.toList());
---
\[appleJuice, apricot!, banana, cherry\]
distinct()
์ค๋ณต ์์๋ฅผ ์ ๊ฑฐํ๋ค.
List names = Arrays.asList("Alice", "Alice", "Bob", "Cindy");
names.stream()
.distinct()
.forEach(System.out::println);
---
\[Alice, Bob, Cindy\]
skip()
์ฒ์ n๊ฐ์ ์์๋ฅผ ๊ฑด๋๋ฐ๊ณ ์ฐ์ฐํ๋ค.
List numbers = Arrays.asList(1,2,3,4,5);
numbers.stream()
.skip(2)
.forEach(System.out::println);
---
3, 4, 5
limit()
์คํธ๋ฆผ์ด ๊ฐ์ ธ์ค๋ ์์ ๊ฐ์๋ฅผ n๊ฐ๋ก ์ ํํ๋ค.
List numbers = Arrays.asList(1,2,3,4,5);
numbers.stream()
.limit(3)
.forEach(System.out::println);
---
1, 2, 3
๐ ๏ธ ์ต์ข ์ฐ์ฐ
forEach()
๊ฐ ์์๋ฅผ ์๋นํ๋ค.
numbers.stream()
.forEach(System.out::println); // ๋ฉ์๋ ๋ ํผ๋ฐ์ค ๋ฐฉ์
numbers.stream()
.forEach(num -> {
System.out.println(num); // ๋๋ค ๋ฐฉ์
}); // ๊ฐ ์์ ์ถ๋ ฅ
collect()
๊ฒฐ๊ณผ๋ฅผ ํน์ ์ปฌ๋ ์ ์ผ๋ก ๋ฐํํ๋ค.
List numbers = Arrays.asList(1, 2, 3);
// ๊ฐ ์์๋ฅผ ์ ๊ณฑํ ๋ฆฌ์คํธ๋ก ๋ฐํ
List squares = numbers.stream()
.map(number -> number\*number)
.collect(Collectors.toList());
// ๋จ์ด๋ฅผ ํค๋ก, ๊ธธ์ด๋ฅผ ๊ฐ์ผ๋ก ํ๋ ๋งต์ผ๋ก ๋ฐํ
List words = Arrays.asList("apple", "banana", "cherry");
Map<String, Integer> result = words.stream()
.collect(Collectors.toMap(word -> word, String::length));
reduce()
๋ชจ๋ ์์๋ฅผ ๊ฒฐํฉํด์ ํ๋์ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํ๋ค.
reduce(์ด๊ธฐ๊ฐ, ๊ฒฐํฉ๋ฐฉ์)๋ฐฉ์์ผ๋ก ์ฌ์ฉํ๋ค.
List numbers = Arrays.asList(1, 2, 3, 4, 5);
//๊ฐ ์์์ ๊ฐ ๋ํ๊ธฐ
int sum = numbers.stream()
.reduce(0, (a,b) -> a + b); //์ด๊ธฐ๊ฐ 0์์๋ถํฐ ๋ ๊ฐ์ ๋ํจ
//์ต๋๊ฐ ๊ตฌํ๊ธฐ
int max = numbers.stream()
.reduce(Integer.MIN\_VALUE, (a, b) -> a > b ? a : b); // Integer.MIN\_VALUE๋ก ์ด๊ธฐํ
anyMatch(), allMatch(), noneMatch()
์ผ์นํ๋ ์์๊ฐ ์๋์ง ์ฐพ๋๋ค. ๊ฒฐ๊ณผ๋ boolean์ผ๋ก ๋ฐํํ๋ค.
- anyMatch(): ์ผ์นํ๋ ์์๊ฐ ํ๋๋ผ๋ ์์ผ๋ฉด true
- allMatch(): ๋ชจ๋ ์์๊ฐ ์กฐ๊ฑด์ ๋ง์กฑํ๋ฉด true
- noneMatch(): ๋ชจ๋ ์์๊ฐ ์กฐ๊ฑด์ ๋ง์กฑ ๋ชปํ๋ฉด true
List names = Arrays.asList("Alice", "Bob", "Cindy", "Daniel", "Edward", "Felilx");
// false
boolean hasLongName = names.stream()
.anyMatch(name -> name.length() > 10);
//true
boolean allShortNames = names.stream()
.allMatch(name -> name.length() < 10);
//true
boolean noNameStartWithZ = names.stream()
.noneMatch(name -> name.startsWith("z")); // "z" ๋ก ์์ํ๋ ์ด๋ฆ์ด ์๋์ง ํ์ธ
findFirst(), findAny()
์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๋ฅผ ๋ฐํํ๋ค.
- findFirst(): ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์ ์ค ์ฒซ ๋ฒ์งธ๋ฅผ ๋ฐํํ๋ค.
- findAny(): ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์ ์ค ํ๋๋ฅผ ๋ฐํํ๋ค. ์์ฐจ ์คํธ๋ฆผ์์๋ ์ฒซ ๋ฒ์งธ ์์๋ฅผ, ๋ณ๋ ฌ ์คํธ๋ฆผ์์๋ ์ด๋ค ์์๋ ์ง ๋ฐํ๋ ์ ์๋ค.
List numbers = Arrays.asList(1, 2, 3, 4, 5);
// 4 ๋ฐํ
Optional first = numbers.stream()
.filter(n -> n > 3) // 3๋ณด๋ค ํฐ ์๋ง ํํฐ๋ง
.findFirst(); // ์ฒซ ๋ฒ์งธ ์์ ๋ฐํ
count()
์คํธ๋ฆผ์์ ์์์ ๊ฐ์๋ฅผ ๋ฐํํ๋ค. filter()์ ํจ๊ป ์ฌ์ฉํด๋ ์ข๋ค.
List numbers = Arrays.asList(1, 2, 3, 4, 5);
int count = numbers.stream()
.count(); // ์คํธ๋ฆผ์ ์์ ๊ฐ์ ์ธ๊ธฐ
int even = numbers.stream()
.filter(n -> n % 2 == 0) // ์ง์๋ง ํํฐ๋ง
.count(); // ํํฐ๋ง๋ ์์์ ๊ฐ์
Map์์ Stream API๋ฅผ ์ฐ๋ ๋ฒ
Stream API๋ ์ปฌ๋ ์
๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋ฉ์๋๋ผ๊ณ ํ๋ค.
์ด ์ปฌ๋ ์
๋ฐ์ดํฐ๋, Collection interface๋ฅผ ๊ตฌํํ๋ ๊ตฌํ์ฒด ๋ฐ์ดํฐ๋ฅผ ๋งํ๋ค.
์ฌ๊ธฐ์ List, Set ๋ฑ์ด ํฌํจ๋๋ค.
๋ค๋ง List์ Set๋งํผ ์์ฃผ ์ฐ๋ Map์ ํฌํจ๋์ง ์๋๋ค!
Collection Interface ์ค Set์ ํ์ฉํ๋ค.
Map์์ ๋์ฌ ๋งํ Set์ key set, value set, entry set์ด๋ค. ๋ชจ๋ Map์ ๋ด์ฅ๋ ๋ฉ์๋๋ฅผ ์ด์ฉํด ๊ตฌํ ์ ์๋ค. ์ด Set ํํ์ ๋ฐ์ดํฐ๋ค๋ก Stream API๋ฅผ ์ฐ๋ฉด ๋๋ค.
- keySet()
- values()
- entrySet()
๐ ์ฐธ๊ณ ์๋ฃ
์ฝ๋์ ์คํ๋ฆฐํธ ๊ฐ์ ๋ ธํธ
์์ฑ์ฑ ๋์ ํฌ์คํ : [Java] Stream API