๐Today...
โ์ค๋์ TIL(Today I Learn)
์คํธ๋ฆผ?
์คํธ๋ฆผ(Stream)์ ์๋ฐ8๋ถํฐ ๋์ ๋ ๋ฌธ๋ฒ์ผ๋ก ๋ฐฐ์ด ๋ฐ ์ปฌ๋ ์ ์ ์ ์ฅ์์๋ฅผ ํ๋์ฉ ์ฐธ์กฐํด์ ๋๋ค์์ผ๋ก ์ฒ๋ฆฌํ ์์๋๋ก ํ๋ ๋ฐ๋ณต์์ด๋ค. for๋ฌธ์ด๋ Iterator๋ฅผ ์ฌ์ฉํ๋๊ฒฝ์ฐ ์ฝ๋๊ฐ ๊ธธ๊ณ ๋ณต์ก ํด์ง์์๋ค. ๋ํ ์ ์ธํ ํ๋ก๊ทธ๋๋ฐ(Declarative Programming) ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ์ฌ ๋ด๋ถ์ ๋์์๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋๋ผ๋ ์ด๋ค ์ฝ๋๊ฐ ์ด๋ค ์ญํ ์ ํ๋์ง ์ง๊ด์ ์ผ๋ก ์ดํด๊ฐ ๊ฐ๋ฅํ๋ค.
์คํธ๋ฆผ์ ํน์ง
- ์คํธ๋ฆผ์ ์ฒ๋ฆฌ๊ณผ์ ์ ์์ฑ, ์ค๊ฐ์ฐ์ฐ, ์ต์ข ์ฐ์ฐ 3๋จ๊ณ์ ํ์ดํ๋ผ์ธ์ผ๋ก ๊ตฌ์ฑ๊ฐ๋ฅํ๋ค.
- ์คํธ๋ฆผ์ ์๋ณธ๋ฐ์ดํฐ์ ์์ค๋ฅผ ๋ณ๊ฒฝํ์ง์๋๋ค.(read-only)
- ์คํธ๋ฆผ์ 1ํ์ฉ์ด๋ค.(ontime-only)
- ์คํธ๋ฆผ์ ๋ด๋ถ๋ฐ๋ณต์์ด๋ค.
์ธ๋ถ๋ฐ๋ณต์ : ๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ก ์ง์ ์ปฌ๋ ์ ์ ์์๋ฅผ ๋ฐ๋ณตํด์ ๊ฐ์ ธ์ค๋ ์ฝ๋ํจํด => for, while
๋ด๋ถ๋ฐ๋ณต์ : ์ปฌ๋ ์ ๋ด๋ถ์์ ์์๋ค์ ๋ฐ๋ณต์ํค๊ณ , ๊ฐ๋ฐ์๋ ์์๋น ์ฒ๋ฆฌํ ์ฝ๋๋ง ์ ๊ณตํ๋ ํจํด
->๋ณ๋ ฌ์ฒ๋ฆฌ : ํ๊ฐ์ง ์์ ์ ์๋ธ์์ ์ผ๋ก ๋๋๊ณ , ์๋ธ์์ ๋ค์ ๋ถ๋ฆฌ๋ ์ค๋ ๋์์ ๋ณ๋ ฅ์ ์ผ๋ก ์ฒ๋ฆฌํ๋๊ฒ
์คํธ๋ฆผ "์์ฑ"
์คํธ๋ฆผ์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ์ํด์ ๊ฐ์ฅ๋จผ์ ์คํธ๋ฆผ์ ์์ฑํด์ผํ๋ค. ๊ทธ๋ฐฉ๋ฒ์ ์ ๋ฆฌํด๋ณด์๋ค.
# ๋ฐฐ์ด ์คํธ๋ฆผ ์์ฑ
public class StreamCreator {
public static void main(String[] args) {
// ๋ฌธ์์ด ๋ฐฐ์ด ์ ์ธ ๋ฐ ํ ๋น
String[] arr = new String[]{"๋ง๋๋ฐฐ", "๊ธธ๋๊ทผ", "๊น๋ณต์ถ"};
Stream<String> stream1 = Arrays.stream(arr); //๋ฌธ์์ด ์คํธ๋ฆผ ์์ฑ1
Stream<String> stream2 = Arrays.of(arr) //๋ฌธ์์ด ์คํธ๋ฆผ ์์ฑ2
}
}
# ์ซ์ํ ์คํธ๋ฆผ
1. int์์ : IntStream
2. double์์ : DoubleStream
3. long์์ : LongStream
# ์ปฌ๋ ์ ์คํธ๋ฆผ ์์ฑ
์ปฌ๋ ์ ํ์ (List, Set ๋ฑ) ์ ์ต์์ ํด๋์ค์ธ Collection์ ์ ์๋ Stream()๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์คํธ๋ฆผ์ ์์ฑํ ์์๋ค.
public class StreamCreator {
public static void main(String[] args) {
// ์์๋ค์ ๋ฆฌ์คํธ
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); //๋ฐฐ์ด์ ๋ฆฌ์คํธ๋ก ๋ณ๊ฒฝ
Stream<Integer> stream = list.stream(); //Integerํ stream ์์ฑ
}
}
์คํธ๋ฆผ "์ค๊ฐ์ฐ์ฐ"
์ค๊ฐ์ฐ์ฐ์(Intermediate Operation)๋ฅผ ์ฐ์ฐํ ๊ฒฐ๊ณผ๋ฅผ ์คํธ๋ฆผ์ผ๋ก ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์ฌ๋ฌ๊ฐ์ ์ฐ์ฐ์๋ฅผ ์ฐ๊ฒฐํ์ฌ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๋ฐ์ดํฐ์ฒ๋ฆฌ๋ฅผ ์ํํ ์ ์๋ค. ๋ฐ์ดํฐ๋ฅผ Stream์ผ๋ก ๋ฐ์ Stream ํ์์ผ๋ก ๊ฐ๊ณตํด์ค๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค.
# ํํฐ๋ง
public class FilteringExample {
public static void main(String[] args) throws Exception {
List<String> names = Arrays.asList("๋ฐ์ถ๋ฐฐ", "๊ธธ๋๊ทผ", "ํธ๋ ๋");
names.stream()
.distinct() //์ค๋ณต์ ๊ฑฐ
.filter(element -> element.startsWith("๊ธธ")) // ๊ธธ์จ ์ฑ์ ๊ฐ์ง ์์๋ง ํํฐ๋ง
.forEach(element -> System.out.println(element)); //์ต์ข
์ฐ์ฐ forEach
}
}
filter() : stream์์ ์กฐ๊ฑด์ ๋ง๋ ๋ฐ์ดํฐ๋ง์ ์ ์ ํ์ฌ ๋์์ ์ปฌ๋ ์ ์ ๋ฑ์ด๋ธ๋ค. filter()์ ๋งค๊ฐ๊ฐ์ผ๋ก ์กฐ๊ฑด(Predicate)๋ฅผ ์ฃผ๊ณ ์ฐธ์ด๋๋ ์์๋ง ํํฐ๋งํ๋ค. ์กฐ๊ฑด์ ๋๋ค์์ ์ฌ์ฉํ์ฌ ์ ์ํ ์์๋ค.
distinct() : ์ค๋ณต์ ์ ๊ฑฐํ๋ค.
# ๋งคํ
๋งคํ์ ์คํธ๋ฆผ๋ด ์์๋ค์์ ์ํ๋ ํ๋๋ง ์ถ์ถํ๊ฑฐ๋ ํน์ ํํ๋ก ๋ณํํ ๋ ์ฌ์ฉํ๋ค. filter์ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ฐ์ ๋ณํํ๊ธฐ ์ํ ์กฐ๊ฑด์ ๋๋ค์์ผ๋ก ์ ์ํ๋ค.
public class IntermediateOperationExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("guri", "daejeon", "seoul");
List<Integer> list = Arrays.asList(1, 3, 6, 9);
names.stream()
.map(element -> element.toUpperCase()) // ์์๋ค์ ํ๋์ฉ ๋๋ฌธ์๋ก ๋ณํ
.forEach(element->System.out.println(element));
list.stream()
.map(number -> number * 3) //์์๋ค์ 3์ ๊ณฑํ๊ฐ์ ๋ฐํ
.forEach(System.out::println);
}
}
map() : ์๋จ ์ฝ๋ ์ฐธ์กฐ..!
flatMap() : ์ค์ฒฉ๊ตฌ์กฐ๋ฅผ ์ ๊ฑฐํ๊ณ ๋จ์ผ์ปฌ๋ ์ ์ผ๋ก ๋ง๋ค์ด์ฃผ๋ ์ญํ ์ ํ๋ค. ๋ฐฐ์ด์ depth๊ฐ ์กด์ฌํ ๋ ํจ์จ์ ์
# ์ ๋ ฌ
public class IntermediateOperationExample {
public static void main(String[] args) {
// ๋๋ฌผ๋ค์ ์ด๋ฆ์ ๋ชจ์๋ ๋ฆฌ์คํธ
List<String> animals = Arrays.asList("Tiger", "Lion", "Monkey", "Duck", "Horse", "Cow");
animals.stream().sorted().forEach(System.out::println); // ์ธ์๊ฐ ์๋ sorted() ํธ์ถ(์ค๋ฆ์ฐจ์)
animals.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println); //์ญ์์ผ๋ก ์ ๋ ฌ
}
}
# ๊ธฐํ
skip() : ์คํธ๋ฆผ์ ์ผ๋ถ์์๋ฅผ ๊ฑด๋๋ด๋ค.
limit() : ์คํธ๋ฆผ์ ์ผ๋ถ๋ฅผ ์๋ฅธ๋ค.
peak() : ์์๋ค์ ์ํํ๋ฉฐ ํน์ ์์ ์ ์ํ (forEach์ ์ค๊ฐ์ฐ์ฐ์ ๋ฒ์ ?)
์คํธ๋ฆผ "์ต์ข ์ฐ์ฐ"
์ต์ข ์ฐ์ฐ(Terminal Operation)์ Streamํ์ดํ๋ผ์ธ์์ ์ต์ข ์ ์ผ๋ก ์ฌ์ฉ๋๊ณ , ํด๋น ์คํธ๋ฆผ์ด ๋ซํ๋ฉฐ ๋ชจ๋ ์ฐ์ฐ์ด ์ข ๋ฃ๋๋ค. ์ค๊ฐ์ฐ์ฐ์ ์ต์ข ์ฐ์ฐ์๊ฐ ์ํ๋ ๋ ์คํธ๋ฆผ์ ์์๋ค์ด ์ค๊ฐ์ฐ์ฐ์ ๊ฑฐ์ณ ์ต์ข ์ฐ์ฐ์์ ์๋ชจ๋๋ค. ์ด๋ฅผ ์ง์ฐ๋ ์ฐ์ฐ(Lazy evaluation) ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค. ์ต์ข ์ฐ์ฐ์ ๊ฒฐ๊ณผ๋ Stream์ผ๋ก ๋ฐํ๋์ง์๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ต์ข ์ฐ์ฐ์ ํ๋ฒ๋ง ๊ฐ๋ฅํ๋ค.
# ๊ธฐ๋ณธ์ง๊ณ
count() : ์คํธ๋ฆผ ์์์ ์ด๊ฐ์๋ฅผ longํ์ ์ ๊ฐ์ผ๋ก ๋ฐํํ๋ค.
max(), min() : ์คํธ๋ฆผ์ ์์์ค ๊ฐ์ฅ ํฐ๊ฐ๊ณผ ์์ ๊ฐ์ ๊ฐ์ง๋ ์์๋ฅผ ์ฐธ์กฐํ๋ Optional ๊ฐ์ฒด๋ฅผ ์ป๋๋ค.
sum(), average() : IntStream, DoubleStream ๊ณผ ๊ฐ์ ๊ธฐ๋ณธ ํ์ ์คํธ๋ฆผ์ ์กด์ฌํ๋ฉฐ ํฉ๊ณผ ํ๊ท ์ ๊ตฌํ๋ค. average()๋ ๊ธฐ๋ณธํ์ ์ผ๋ก ๋ํ๋ Optional ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
long countEx = stream.count();
int maxEx = stream.max().getAsInt();
int sumEx = stream.sum()
int averageEx = stream.average().getAsInt(); //Optional๊ฐ์ฒด๋ก ๋ฐํ๋๋ฉด getAS์ฌ์ฉ..!
# ๋งค์นญ match()
Stream ์์๋ค์ ํน์ ํ ์กฐ๊ฑด์ ์ถฉ์กฑํ๋์ง ๊ฒ์ฌํ๋ค. ์กฐ๊ฑด์ ๋๋ค Predicate๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋๊ฒจ ์คํธ๋ฆผ์ ๊ฐ ๋ฐ์ดํฐ ์์๊ฐ ํน์ ํ ์กฐ๊ฑด์ ์ถฉ์กฑํ๋์ง ๊ฒ์ฌํ์ฌ ๊ฒฐ๊ณผ๋ฅผ boolean๊ฐ์ผ๋ก ๋ฐํํ๋ค.
allMatch() : ๋ชจ๋ ์์๊ฐ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ์ฌ๋ถ๋ฅผ ํ๋จ
noneMatch() : ๋ชจ๋ ์์๊ฐ ์กฐ๊ฑด์ ๋ง์กฑํ์ง ์๋์ง ์ฌ๋ถ๋ฅผ ํ๋จ
anyMatch() : ํ๋๋ผ๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๊ฐ ์๋์ง ์ฌ๋ถ๋ฅผ ํ๋จ
public class TerminalOperationExample {
public static void main(String[] args) throws Exception {
int[] intArray = {2,4,6}; //๋ฐฐ์ด์ ์ธ
// allMatch()
boolean all = Arrays.stream(intArray).allMatch(element-> element % 2 == 0);
// anyMatch()
boolean any = Arrays.stream(intArray).anyMatch(element-> element % 3 == 0);
// noneMatch()
boolean non = Arrays.stream(intArray).noneMatch(element -> element % 3 == 0);
}
}
# ์์ ์๋ชจ reduce()
reduce() : ์คํธ๋ฆผ์ ์์๋ฅผ ์ค์ฌ๋๊ฐ๋ฉด์ ์ฐ์ฐ์ ์ํํ๊ณ ์ต์ข ์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ค. reduce๋ ๋จผ์ ์ฒซ๋ฒ์งธ์ ๋๋ฒ์งธ ์์๋ฅผ ๊ฐ์ง๊ณ ์ฐ์ฐ์ ์ํํ๊ณ , ๊ทธ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ธ๋ฒ์งธ ์์๋ฅผ ๊ฐ์ง๊ณ ๋๋ค์ ์ฐ์ฐ์ ์ํํ๋ ์์ผ๋ก ๋ฐ๋ณตํ๋ค.
T reduce(T identity, BinaryOperator<T> accumulator)
identity - ํน์ ์ฐ์ฐ์ ์์ํ ๋ ์ค์ ํ๋ ์ด๊ธฐ๊ฐ
accumulator - ๊ฐ์์๋ฅผ ์ฐ์ฐํ์ฌ ๋์จ ๋์ ๋ ๊ฒฐ๊ณผ๊ฐ์ ์์ฑํ๋๋ฐ ์ฌ์ฉํ๋ ์กฐ๊ฑด์
public class TerminalOperationExample {
public static void main(String[] args) throws Exception {
int[] intArray = {1,2,3,4,5};
// sum()
long sum = Arrays.stream(intArray).sum();
// ์ด๊ธฐ๊ฐ์ด ์๋ reduce()
int sum1 = Arrays.stream(intArray)
.map(element -> element * 2)
.reduce((a , b) -> a + b)
.getAsInt();
// ์ด๊ธฐ๊ฐ์ด ์๋ reduce()
int sum2= Arrays.stream(intArray)
.map(element -> element * 2)
.reduce(5, (a ,b) -> a + b);
}
}
//์ด๊ธฐ๊ฐ ์์๋ : 30 , ์ด๊ธฐ๊ฐ์์๋ : 35
#์์์ ์ถ๋ ฅ forEach()
์คํธ๋ฆผ์ ๊ฐ์์๋ฅผ ์๋ชจํ์ฌ ๋ช ์๋ ๋์์ ์ํํ๋ค. ๋ฐํํ์ ์ด void์ฌ์ ๋ณดํต ๋ชจ๋ ์์๋ฅผ ์ถ๋ ฅํ๋ ์ฉ๋๋ก ๋ง์ด ์ฌ์ฉํ๋ค.
public class FilteringExample {
public static void main(String[] args) throws Exception {
List<String> names = Arrays.asList("๊ธธ๋๊ทผ", "๊ธธ๋๊ทผ", "๊ธธ๋๊ทผ", "๊น๋ํ", "๋ฐ์ ์ฒ");
names.stream()
.distinct() //์ค๋ณต ์ ๊ฑฐ
.forEach(element -> System.out.println(element)); //forEach์ฌ์ฉ..
}
}
# ์์์ ๊ฒ์ find()
findFirst() : ํด๋น ๋ฉ์๋๋ ํด๋น ์คํธ๋ฆผ์์ ์ฒซ ๋ฒ์งธ ์์๋ฅผ ์ฐธ์กฐํ๋ Optional๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. ๋น์ด์๋ ์คํธ๋ฆผ์์๋ ๋น์ด์๋ Optional ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
findAny() : ๋ณ๋ ฌ์คํธ๋ฆผ์ธ ๊ฒฝ์ฐ์๋ findAny()๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ผ ์ ํํ๋ค.
int result1 = stream1.findFirst().getAsInt(); // ์ฒซ ๋ฒ์จฐ ์์ ๋ฐํ
# ์์ ์์ง collect()
collect() ๋ฉ์๋๋ ์์๋ค์ ์์งํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ์ฌ ์ต์ข ์ฒ๋ฆฌํ๋ ๋ฉ์๋์ด๋ค. ์คํธ๋ฆผ์ ์์๋ค์ List, Set, Map๋ฑ ๋ค๋ฅธ ํ์ ์ ๊ฒฐ๊ณผ๋ก ์์งํ๊ณ ์ถ์ ๊ฒฝ์ฐ์ collect() ๋ฉ์๋๋ฅผ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์์๋ค collect()๋ฉ์๋๋ Collector ์ธํฐํ์ด์ค ํ์ ์ ์ธ์๋ฅผ ๋ฐ์์ ์ฒ๋ฆฌํ ์์์ผ๋ฉฐ, ์ด๋ ์ง์ ๊ตฌํํ๊ฑฐ๋ ๋ฏธ๋ฆฌ ์ ๊ณต๋ ๊ฒ๋ค์ ์ฌ์ฉํ ์ ์๋ค.
์คํธ๋ฆผ์ ๋ฐฐ์ด์ด๋ ์ปฌ๋ ์ ์ผ๋ก ๋ณํ : toArray(), toCollection(), toList(), toSet(), toMap()
์์์ ํต๊ณ์ ์ฐ์ฐ ๋ฉ์๋์ ๊ฐ์ ๋์์ ์ํ : counting(), maxBy(), minBy(), summingint(), averagingInt()
์์์ ์๋ชจ์ ๊ฐ์ ๋์์ ์ํ : reducing(), joining()
์์์ ๊ทธ๋ฃนํ์ ๋ถํ : groupingBy(), partitioningBy()
Stream<String> stream = Stream.of("์ผ", "์ด", "์ผ", "์ฌ");
List<String> list = stream.collect(Collectors.toList()); //list๋ก ๋ณ๊ฒฝ
// ์คํธ๋ฆผ ์ฐ์ฐ ๊ฒฐ๊ณผ๋ฅผ Map์ผ๋ก ๋ฐํ
Map<String, Integer> maleMap = totalList.stream()
.filter(s -> s.getGender() == Student.Gender.Male)
.collect(Collectors.toMap(
student -> student.getName(), // Key
student -> student.getScore() // Value
));
๐ํผ์์ ํด๊ฒฐํ๊ธฐ
Stream ์ฐ์ต๋ฌธ์ ํ์ด
2023.05.04 - [My Thinking๐] - 2023.05.04 TIL - Stream ์ฐ์ต๋ฌธ์ ์ ๋ฆฌ (1 ~ 13๋ฒ)