โ๏ธ Stream์ด๋?
๐ก ์ ์
- ์คํธ๋ฆผ์ Java 8์์ ์ถ๊ฐ๋ ๊ธฐ๋ฅ
- ์คํธ๋ฆผ์ ๋ฐ์ดํฐ์ ํ๋ฆ, ์ปฌ๋ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ธํ์ผ๋ก ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์์
- ๋ฃจํ๋ฌธ/๋ฃจํ๋ฌธ ์ค์ฒฉ์ ์ฌ์ฉํ์ง ์์๋ ๋จ
- ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ๋ณ๋์ ๋ฉํฐ์ฐ๋ ๋ ์์ด ๊ตฌํํ ์ ์์
๐ฎ ์ฅ์
- ์ ์ธํ์ด๊ธฐ ๋๋ฌธ์ ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง๊ณ ๊ฐ๋ ์ฑ์ด ์ข์์ง
- ์ ์ฐ์ฑ์ด ์ข์์ง
- ๋ณ๋ ฌํ๋ก ์ธํด ์ฑ๋ฅ์ด ์ข์์ง
โ๏ธ ์คํธ๋ฆผ์ ํฌ๊ฒ 3๊ฐ์ง๋ก ๋๋ ์ ์๋ค.
- ์์ฑํ๊ธฐ : ์คํธ๋ฆผ ์ธ์คํด์ค ์์ฑ
- ๊ฐ๊ณตํ๊ธฐ : ํํฐ๋ง ๋ฐ ๋งตํ ๋ฑ ์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด๊ฐ๋ ์ค๊ฐ ์์
- ๊ฒฐ๊ณผ ๋ง๋ค๊ธฐ : ์ต์ข ์ ์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด๋ด๋ ์์
โ๏ธ ์์ฑํ๊ธฐ
๋ฐฐ์ด ์คํธ๋ฆผ
์คํธ๋ฆผ์ ๋ฐฐ์ด ๋๋ ์ปฌ๋ ์ ์ธ์คํด์ค๋ฅผ ์ด์ฉํด์ ์์ฑํ ์ ์๋ค. ๋ฐฐ์ด์ ๋ค์๊ณผ ๊ฐ์ด Arrays.stream ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค.
String[] alphabet = new String[]{"A", "B", "C"};
Stream<String> stream = Arrays.stream(alphabet);
Stream<String> streamOfPart = Arrays.stream(alphabet, 0, 2); // 0~1 ์์ [A, B]
์ปฌ๋ ์ ์คํธ๋ฆผ
์ปฌ๋ ์ ํ์ ์ ์ธํฐํ์ด์ค์ ์ถ๊ฐ๋ ๋ํดํธ ๋ฉ์๋ stream()์ ์ด์ฉํด์ ์คํธ๋ฆผ์ ๋ง๋ค ์ ์๋ค.
List<String> alphabet = Arrays.asList("A", "B", "C");
Stream<String> stream = alphabet.stream();
Stream<String> parallelStream = alphabet.parallelStream();
๋น์ด์๋ ์คํธ๋ฆผ
๋น ์คํธ๋ฆผ์ ์์๊ฐ ์์ ๋ null ๋์ ์ฌ์ฉํ ์ ์๋ค.
public Stream<String> streamOf(List<String> list) {
return list == null || list.isEmpty()
? Stream.empty()
: list.stream();
}
Stream.builder()
๋น๋๋ฅผ ์ฌ์ฉํ๋ฉด ์คํธ๋ฆผ์ ์ง์ ์ ์ผ๋ก ์ํ๋ ๊ฐ์ ๋ฃ์ ์ ์๋ค. ๋ง์ง๋ง์ build() ๋ฉ์๋๋ก ์คํธ๋ฆผ์ ๋ฆฌํดํ๋ค.
Stream<String> builderStream =
Stream.<String>builder()
.add("A").add("B").add("C")
.build(); // [A, B, C]
Stream.generate()
generate() ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด Supplier<T>์ ํด๋นํ๋ ๋๋ค๋ก ๊ฐ์ ๋ฃ์ ์ ์๋ค. Supplier<T>๋ ์ธ์๋ ์๊ณ ๋ฆฌํด๊ฐ๋ง ์๋ ํจ์ํ ์ธํฐํ์ด์ค๋ค. ๋๋ค์์ ๋ฆฌํดํ๋ ๊ฐ์ด ๋ค์ด๊ฐ๋ค.
Stream<String> generatedStream =
Stream.generate(() -> "A").limit(3); // [A, A, A]
Stream.iterate()
iterate() ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด ์ด๊ธฐ๊ฐ๊ณผ ํด๋น๊ฐ์ ๋ค๋ฃจ๋ ๋๋ค๋ฅผ ์ด์ฉํด์ ์คํธ๋ฆผ์ ๋ค์ด๊ฐ ์์๋ฅผ ๋ง๋ ๋ค. ๋ค์ ์์ ์์๋ ์ด๊ธฐ๊ฐ์ด 1์ด๊ณ , ๊ฐ์ด 2์ฉ ์ฆ๊ฐํ๊ฒ ๋๋ค. ์คํธ๋ฆผ์ ์ฌ์ด์ฆ๋ ๋ฌดํ์ด๊ธฐ ๋๋ฌธ์ limit()์ผ๋ก ์ ํํด์ผ ํ๋ค.
Stream<Integer> iteratedStream =
Stream.iterate(1, n -> n + 2).limit(5); // [1, 3, 5, 7, 9]
์คํธ๋ฆผ ์ฐ๊ฒฐํ๊ธฐ
Stream.concat() ๋ฉ์๋๋ฅผ ์ด์ฉํด ๋ ๊ฐ์ ์คํธ๋ฆผ์ ์ฐ๊ฒฐํ ์ ์๋ค.
Stream<String> stream1 = Stream.of("1", "2", "3");
Stream<String> stream2 = Stream.of("A", "B", "C");
Stream<String> concat = Stream.concat(stream1, stream2); // [1, 2, 3, A, B, C]
โ๏ธ ๊ฐ๊ณตํ๊ธฐ
์ ์ฒด ์์ ์ค ๋ค์๊ณผ ๊ฐ์ API๋ฅผ ์ด์ฉํด ์ํ๋ ๊ฒ๋ง ๋ฝ์๋ผ ์ ์๋ค. ์ด๋ฌํ ๋จ๊ณ๋ฅผ ์ค๊ฐ ์์ ์ด๋ผ ํ๋๋ฐ, ์คํธ๋ฆผ์ ๋ฆฌํดํ๊ธฐ ๋๋ฌธ์ ์ฌ๋ฌ ์์ ์ ์ด์ด ๋ถ์ฌ์(chaining) ์์ฑํ ์ ์๋ค.
List<String> alphabet = Arrays.asList("A", "B", "C"); // [A, B, C]
Filtering
ํํฐ๋ ์คํธ๋ฆผ ๋ด ์์๋ค์ ํ๋์ฉ ํ๊ฐํ๋ฉฐ ๊ฑธ๋ฌ๋ด๋ ์์ ์ด๋ค. ์ธ์๋ก ๋ฐ๋ Predicate๋ boolean์ ๋ฆฌํดํ๋ ํจ์ํ ์ธํฐํ์ด์ค๋ก ํ๊ฐ์์ด ๋ค์ด๊ฐ๊ฒ ๋๋ค.
Stream<String> stream =
alphabet.stream()
.filter(a -> a.contains("A")); // [AAA, Aa, aaA]
์คํธ๋ฆผ์ ๊ฐ ์์์ ๋ํด ํ๊ฐ์์ ์คํํ๊ฒ ๋๊ณ 'A'๊ฐ ๋ค์ด๊ฐ ๋จ์ด๋ง ๋ฆฌํดํ๋ค.
Mapping
๋งต์ ์คํธ๋ฆผ ๋ด ์์๋ค์ ํ๋์ฉ ํน์ ๊ฐ์ผ๋ก ๋ณํํ๋ค. ์ด ๋ ๊ฐ์ ๋ณํํ๊ธฐ ์ํ ๋๋ค๋ฅผ ์ธ์๋ก ๋ฐ๋๋ค.
Stream<String> stream =
alphabet.stream()
.map(String::toLowerCase); // [a, b, c]
์คํธ๋ฆผ ๋ด String์ toLowerCase() ๋ฉ์๋๋ฅผ ์คํํด ๋๋ฌธ์๋ก ๋ณํํ ๊ฐ๋ค์ด ๋ด๊ธด ์คํธ๋ฆผ์ ๋ฆฌํดํ๋ค.
์ด์ธ์๋ ์กฐ๊ธ ๋ ๋ณต์กํ flatMap() ๋ฉ์๋๊ฐ ์๋ค.
List<List<String>> list =
Arrays.asList(Arrays.asList("A"), Arrays.asList("B"));
๋ค์๊ณผ ๊ฐ์ด ์ค์ฒฉ๋ ๋ฆฌ์คํธ๋ฅผ flatMap()์ ์ฌ์ฉํด ์ค์ฒฉ ๊ตฌ์กฐ๋ฅผ ์ ๊ฑฐํ ์ ์๋ค.
List<String> flatList =
list.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList()); // [A, B]
Sorting
์ ๋ ฌ์ Comparator์ ์ด์ฉํ๋ค. ์ธ์ ์์ด ํธ์ถํ ๊ฒฝ์ฐ ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ ฌํ๋ค.
IntStream.of(1, 2, 3, 4, 5)
.sorted()
.boxed()
.collect(Collectors.toList()); // [1, 2, 3, 4, 5]
๋ค์์ ์ธ์๋ฅผ ๋๊ธฐ๋ ๊ฒฝ์ฐ์ด๋ค.
List<String> alphabet =
Arrays.asList("A", "B", "C", "D", "E", "F");
alphabet.stream()
.sorted()
.collect(Collectors.toList()); // [A, B, C, D, E, F]
alphabet.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList()); // [F, E, D, C, B, A]
Comparatord์ compare() ๋ฉ์๋๋ ๋ ์ธ์๋ฅผ ๋น๊ตํด ๊ฐ์ ๋ฆฌํดํ๋ค.
alphabet.stream()
.sorted(Comparator.comparingInt(String::length))
.collect(Collectors.toList()); // [apple, banana, bluberry]
alphabet.stream()
.sorted((s1, s2) -> s2.length() - s1.length())
.collect(Collectors.toList()); // [bluberry, banana, apple]
โ๏ธ ๊ฒฐ๊ณผ ๋ง๋ค๊ธฐ
๊ฐ๊ณตํ ์คํธ๋ฆผ์ผ๋ก ์ฌ์ฉํ ๊ฒฐ๊ณผ๊ฐ์ ๋ง๋ค์ด๋ด๋ ๋จ๊ณ์ด๋ค. ๋ฐ๋ผ์ ์คํธ๋ฆผ์ ๋๋ด๋ ์ต์ข ์์ ์ด๋ค.
Calculating
์คํธ๋ฆผ API๋ ๋ค์ํ ์ต์ข ์์ ์ ์ ๊ณตํ๋ค. ์ต๋, ์ต์, ํฉ, ํ๊ท ๋ฑ ๊ธฐ๋ณธํ ํ์ ์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด๋ผ ์ ์๋ค.
long count = IntStream.of(1, 3, 5, 7, 9).count();
long sum = LongStream.of(1, 3, 5, 7, 9).sum();
๋ง์ฝ ์คํธ๋ฆผ์ด ๋น์ด์๋ ๊ฒฝ์ฐ count()์ sum()์ 0์ ์ถ๋ ฅํ๋ฉด ๋๋ค. ํ์ง๋ง ์ต๋, ์ต์, ํ๊ท ์ ๊ฒฝ์ฐ ํํํ ์ ์๊ธฐ ๋๋ฌธ์ Optional์ ์ด์ฉํด ๋ฆฌํดํ๋ค.
OptionalInt min = IntStream.of(1, 3, 5, 7, 9).min();
OptionalInt max = IntStream.of(1, 3, 5, 7, 9).max();
์คํธ๋ฆผ์์ ๋ฐ๋ก ifPresent ๋ฉ์๋๋ฅผ ์ด์ฉํด Optional์ ์ฒ๋ฆฌํ ์ ์๋ค.
DoubleStream.of(1.1, 2.2, 3.3, 4.4, 5.5)
.average()
.ifPresent(System.out::println);
Collecting
collect() ๋ฉ์๋๋ ๋ ๋ค๋ฅธ ์ต์ข ์์ ์ด๋ค. Collector ํ์ ์ ์ธ์๋ฅผ ๋ฐ์์ ์ฒ๋ฆฌํ๋ค.
๋ค์ ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ์ฌ collect() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค.
List<Product> productList =
Arrays.asList(new Product(1, "apple"),
new Product(2, "banana"),
new Product(3, "orange"),
new Product(4, "bluberry");
Collectors.toList()
์คํธ๋ฆผ์์ ์์ ํ ๊ฒฐ๊ณผ๋ฅผ ๋ด์ ๋ฆฌ์คํธ๋ฅผ ๋ฐํํ๋ค. map()์ผ๋ก ๊ฐ ์์์ ์ด๋ฆ์ ๊ฐ์ ธ์จ ํ Collectors.
List<String> collectorCollection =
productList.stream()
.map(Product::getName)
.collect(Collectors.toList()); // [apple, banana, orange, bluberry]
Collectors.joining()
์คํธ๋ฆผ์์ ์์ ํ ๊ฒฐ๊ณผ๋ฅผ ํ๋์ ์คํธ๋ง์ผ๋ก ์ด์ด๋ถ์ผ ์ ์๋ค.
String listToString =
productList.stream()
.map(Product::getName)
.collect(Collectors.joining()); // applebananaorangebluberry
Collectors.groupingBy()
ํน์ ์กฐ๊ฑด์ผ๋ก ์์๋ค์ ๊ทธ๋ฃนํํ ์ ์๋ค.
Map<Integer, List<Product>> collectorMapOfLists =
productList.stream()
.collect(Collectors.groupingBy(Product::getAmount));
Calculating
์คํธ๋ฆผ API๋ ๋ค์ํ ์ต์ข ์์ ์ ์ ๊ณตํ๋ค. ์ต๋, ์ต์, ํฉ, ํ๊ท ๋ฑ ๊ธฐ๋ณธํ ํ์ ์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด๋ผ ์ ์๋ค.
Matching
๋งค์นญ์ ์กฐ๊ฑด์ ๋๋ค Predicate๋ฅผ ๋ฐ์ ํด๋น ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๊ฐ ์๋์ง ์ฒดํฌํ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ๋ค. ๋ค์๊ณผ ๊ฐ์ 3๊ฐ์ง ๋ฉ์๋๊ฐ ์๋ค.
- anyMatch() : ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๊ฐ ์๋์ง
- allMatch() : ๋ชจ๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง
- noneMatch() : ๋ชจ๋ ์กฐ๊ฑด์ ๋ง์กฑํ์ง ์๋์ง
List<String> fruits = Arrays.asList("apple", "banana", "blueberry");
boolean anyMatch = fruits.stream()
.anyMatch(fruit -> fruit.contains("a")); // true
boolean allMatch = fruits.stream()
.allMatch(fruit -> fruit.length() > 3); // true
boolean noneMatch = fruits.stream()
.noneMatch(fruit -> fruit.endsWith("s")); // true
Iterating
forEach() ์์๋ฅผ ๋๋ฉด์ ์คํ๋๋ ์ต์ข ์์ ์ด๋ค. ๋ณดํต println() ๋ฉ์๋๋ฅผ ๋๊ฒจ์ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ ๋ ์ฌ์ฉํ๋ค.
alphabets.stream().forEach(System.out::println);
์ ๋ด์ฉ์ ๋ค์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํ์์ต๋๋ค.
https://futurecreator.github.io/2018/08/26/java-8-streams/
Java ์คํธ๋ฆผ Stream (1) ์ด์ ๋ฆฌ
์ด๋ฒ ํฌ์คํธ์์๋ Java 8์ ์คํธ๋ฆผ(Stream)์ ์ดํด๋ด ๋๋ค. ์ด ๋ ๊ฐ์ ํฌ์คํธ๋ก, ๊ธฐ๋ณธ์ ์ธ ๋ด์ฉ์ ์ด์ ๋ฆฌํ๋ ์ด๋ฒ ํฌ์คํธ์ ์ข ๋ ๊ณ ๊ธ ๋ด์ฉ์ ๋ค๋ฃจ๋ ๋ค์ ํฌ์คํธ๋ก ๋๋์ด์ ธ ์์ต๋๋ค. Java ์คํธ
futurecreator.github.io
'Language > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Java] JVM ๋์ ๊ณผ์ (0) | 2024.12.04 |
---|---|
[Java] enum (0) | 2023.11.10 |
[Java] ์ผ๊ธ ์ปฌ๋ ์ (2) | 2023.10.26 |