# Stream
# 1. Stream ์๊ฐ
์ฐ์๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ์คํผ๋ ์ด์ ๋ค์ ๋ชจ์
๐ผ ์ด๋ฏธ์ง ์ถ์ฒ (opens new window)
stream
์์ปจ๋ฒ ์ด์ด ๋ฒจํธ
์ ๋น์ทํ๋ค.- ์ปจ๋ฒ ์ด์ด ๋ฒจํธ์ ๋ก์กฐ๊ฐ(๋ฐ์ดํฐ)๋ค์ ํ๋ ค๋ณด๋ด๋ฉด์ ๋ฐ์ฃฝ์ ํ๊ณ , ์๊ธ์ ์๊ณ (map), ๋ถ๋ํ์ ๋นผ๊ณ (filter) ํฌ์ฅ์ ํด์(collect) ๋ด๋ณด๋ธ๋ค.
# 1-1. Stream์ ํน์ง
- ๋ฐ์ดํฐ๋ฅผ ๋ด๊ณ ์๋ ์ ์ฅ์(์ปฌ๋ ์ )์ด ์๋๋ค.
- Functional in nature.
- stream์ ์ฒ๋ฆฌํ๋ ๋ฐ์ดํฐ ์์ค๋ฅผ ๋ณ๊ฒฝํ์ง ์๋๋ค.
- ์ฆ ๋ด๊ฐ
A
๋ผ๋ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ค๊ณ ํด์ ์๋ณธ๋ฐ์ดํฐ๊ฐ ์์ ๋๋ ๊ฒ์ ์๋๋ผ๋ ์๋ฏธ!
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("yj");
Stream<String> stringStream = names.stream().map(String::toUpperCase);
names.forEach(System.out::println);
}
/*
[์คํ ๊ฒฐ๊ณผ]
yj
*/
์คํธ๋ฆผ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐ์ดํฐ๋ ์ค์ง ํ ๋ฒ๋ง ์ฒ๋ฆฌํ๋ค.
- ์ปจ๋ฒ ์ด์ด ๋ฒจํธ์์ ๋ฐ์ดํฐ๋ค์ด ํ ๋ฒ ์ง๋๊ฐ๋ค ๋ค์ ๋์์ค์ง ์์.
๋ฌด์ ํ์ ๋ฐ์ดํฐ์ผ์๋ ์๋ค.
- ์ด ๊ฒฝ์ฐ Short Circuit ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ์ ํํ ์ ์์ต๋๋ค.
์ค๊ฐ ์คํผ๋ ์ด์ ์ ๊ทผ๋ณธ์ ์ผ๋ก
lazy
ํ๋ค.- ์ฌ๋ฌ ์ค๊ฐ ์คํผ๋ ์ด์ ๋ค์ ๋ฉ์๋ ์ฒด์ด๋์ ํ๋๋ผ๋ ๊ทธ ์์ ์์ ์ฝ๋๊ฐ ์ํ๋์ง๋ ์์.
- ๋ชจ๋ ์ค๊ฐ ์คํผ๋ ์ด์ ์ ์คํ ์๊ธฐ๋ ์ข ๋ฃ ์คํผ๋ ์ด์ ์ ํธ์ถ์์ !
- ๋ฐ๋ผ์ ์ค๊ฐ ์คํผ๋ ์ด์ ์ ๋ฐํํ์ ์ ๋ ๋ค๋ฅธ stream
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("yj");
names.add("youngjun");
names.add("spring");
names.add("java8");
Stream<String> stringStream = names.stream().map(s->{
System.out.println(s);
return s.toUpperCase();
});
names.forEach(System.out::println);
}
names.stream().map(s->{ ... });
- stream์ ์ค๊ฐ์คํผ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ์๊ฐ์๋ ์ฝ๋๊ฐ ์ํ๋์ง ์์ต๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ค๊ฐ์คํผ๋ ์ด์ map ์์ ์๋ ์ถ๋ ฅ๋ฌธ์ด ์ํ๋์ง ์์ต๋๋ค. ์ํ์ํค๊ธฐ์ํด์๋ ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ์ ์ํด์ผํฉ๋๋ค.
- ์์ฝ๊ฒ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋ค.
- ์ง๊ธ๊ป ๊ตฌํํ ๋๋ถ๋ถ์ ์์ ์ฝ๋์์๋ forEach๋ฅผ ํตํด ๋จ์ํ ๋ฐ๋ณต ์ถ๋ ฅํ๋ค.
- ๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์ ์กฐ๊ฑด๋ฌธ์ด ์ถ๊ฐ๋๊ณ ๋ก์ง์ด ์ถ๊ฐ๋ ์๋ก stream์ ํตํด ๊ตฌํํ ์๋ก ๊ฐ๊ฒฐํด์ง๊ธฐ ๋๋ฌธ์ stream์ ์ฐ๋ ๊ฒ ์ธ์๋ ๊ธฐ๋ณธ์ ์ธ for๋ฌธ์ด๋ for-of๋ฌธ์ผ๋ก๋ ๋ก์ง๋ค์ ๋ณ๋ ฌ์ ์ผ๋ก ์ฒ๋ฆฌํ๋๊ฒ ์ฝ์ง ์๋ค.
- ํ์ง๋ง, parallelStream()์ ์ด์ฉํ๋ฉด ์์ฝ๊ฒ ๋ณ๋ ฌ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋ค.
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("yj");
names.add("youngjun");
names.add("spring");
names.add("java8");
List<String> collect = names.parallelStream().map(s->{
System.out.println(s + " " + Thread.currentThread().getName());
return s.toUpperCase();
}).collect(Collectors.toList());
collect.forEach(System.out::println);
}
์ฃผ์ํ ์
- ์ฌ์ค์ ๋ฉํฐ ์ค๋ ๋๋ฅผ ์ด์ฉํ๋ค๊ณ ์ฑ๋ฅ์ด ๋ฌด์กฐ๊ฑด ์ข์ ๊ฒ์ ์๋๋ฉฐ ์คํ๋ ค ๋๋ ค์ง ๊ฐ๋ฅ์ฑ์ด ๋ ๋๋ค.
- ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๊ทธ๋ฅ
stream
์ ์ฐ๋๊ฒ ๋์ผ๋ฉฐ ์ ๋ง ํฐ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋ ์ฑ๋ฅ ํ ์คํธ ํparallelStream()
์ ์ฌ์ฉํ๋ฉด ๋๋ค.
# 2. ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ
์คํธ๋ฆผ์ด๋ผ๋ ์ปจ๋ฒ ์ด์ด ๋ฒจํธ์ 0๊ฐ ํน์ ๋ค์์ ์ค๊ฐ ์คํผ๋ ์ดํฐ(intermediate operation)๊ณผ ํ๊ฐ์ ์ข ๋ฃ ์คํผ๋ ์ด์ (terminal operation)์ผ๋ก ๊ตฌ์ฑ. ์ด ์คํธ๋ฆผ์ ๋ฐ๋์ ํ๋์ ์ข ๋ฃ ์คํผ๋ ์ด์ ์ด ์์ด์ผ ํ๋ฉฐ, ๋ง์ฝ ์ข ๋ฃ ์คํผ๋ ์ด์ ์ด ์๋ค๋ฉด, ์คํธ๋ฆผ์ ์กด์ฌํ์ง๋ง ์ฝ๋ ์ํ์ ๋์ง ์๋๋ค.
์คํธ๋ฆผ์ ๋ฐ์ดํฐ ์์ค๋ ์ค์ง ํฐ๋ฏธ๋ ์คํผ๋ ์ด์ ์ ์คํํ ๋์๋ง ์ฒ๋ฆฌํ๋ค!
# 2-1. ์ค๊ฐ ์คํผ๋ ์ด์
Stream์ ๋ฆฌํดํ๋ค!
- Stateless/Stateful ์คํผ๋ ์ด์ ์ผ๋ก ๋ ์์ธํ๊ฒ ๊ตฌ๋ถํ ์๋ ์๋ค.
- ๋๋ถ๋ถ Stateless์ง๋ง distinct๋ sorted์ฒ๋ผ ์ด์ ์์ค ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํด์ผ ํ๋ ์คํผ๋ ์ด์ ์ Stateful ์คํผ๋ ์ด์ .
filter, map, limit, skip, sorted, ...
# 2-2. ์ข ๋ฃ ์คํผ๋ ์ด์
Stream์ ๋ฆฌํดํ์ง ์๋๋ค!
collect, allmatch, count, forEach, min, max...
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("hansol");
names.add("toby");
names.add("catsbi");
names.add("mijeong");
List<String> collect = names.stream().map(s -> {
System.out.println(s);
return s.toUpperCase();
}).collect(Collectors.toList());
collect.forEach(System.out::println);
}
# 3. Stream API
stream api๋ฅผ ์์ ๋ฅผ ํตํด ์์๋ณด์.
- ๊ฑธ๋ฌ๋ด๊ธฐ
- Filter(Predicate)
- stream์์ ํน์ ์กฐ๊ฑด(Predicate)์ ๋ง์กฑํ๋ ์๋ฆฌ๋จผํธ๋ง ์๋ก์ด ์คํธ๋ฆผ์ผ๋ก ๋ฐํ
- ๋ณ๊ฒฝํ๊ธฐ
- Map(Function) ๋๋ FlatMap(Function)
- ๊ฐ๊ฐ์ ์์์์ ํน์ ์์๋ง ๊บผ๋ด๊ฑฐ๋ ํน์ ๋ณ๊ฒฝํ์ฌ ์๋ก์ด ์คํธ๋ฆผ์ผ๋ก ๋ฐํ
- flatMap์ ๊ฒฝ์ฐ Array๋ Object๋ก ๋ํ๋์ด์๋ ๋ด์ฉ๋ฌผ์ ๊บผ๋ด์ด ํ๋๋ก ํฉ์น ์คํธ๋ฆผ์ผ๋ก ์์ฑ ํ ๋ฐํ
- ์์ฑํ๊ธฐ
- generate(Supplier) ๋๋ Iterator(T seed, UnaryOperator)
- seed ๋ก๋ถํฐ UnaryOperator ์ ๋ฌด์ ํ์ผ๋ก ๋ฐ๋ณตํ๋ ์คํธ๋ฆผ ๋ฐํ
- ex: ๋๋ค ๋ฌด์ ํ ์คํธ๋ฆผ
- ์คํธ๋ฆผ์ ์๋ ๋ฐ์ดํฐ๊ฐ ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ํ์ธ
- anyMatch(), allMatch(), nonMatch()
- ์คํธ๋ฆผ์ ์๋ฆฌ๋จผํธ๋ฅผ ๋๋ฉฐ ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ํ์ธ
- ex1: ์คํธ๋ฆผ์ ์๋ ๋ชจ๋ ๊ฐ์ด 10๋ณด๋ค ์์์ง ํ์ธ(allMatch)
- ex2: ์คํธ๋ฆผ์ ์ ๋ชฉ ์ค "Test"๊ฐ ๋ค์ด๊ฐ๋ ์ ๋ชฉ์ด ์๋์ง ํ์ธ(anyMatch)
- ๊ฐ์ ์ธ๊ธฐ
- count()
- ex1: 10๋ณด๋ค ์์ ์์ ๊ฐฏ์๋ฅผ ์ผ๋ค.
- ์คํธ๋ฆผ์ ๋ฐ์ดํฐ ํ๋๋ก ๋ญ์น๊ธฐ
- reduce(identity, ByFunction), collect(), sum(), max()
- ex1: ๋ชจ๋ ์ซ์ ํฉ ๊ตฌํ๊ธฐ
- ex2: ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ํ๋์ ๋ฆฌ์คํธ ํน์ Set์ ์ฎ๊ฒจ ๋ด๊ธฐ
public static void main(String[] args) {
List<OnlineClass> springClasses = new ArrayList<>();
springClasses.add(new OnlineClass(1, "spring boot", true));
springClasses.add(new OnlineClass(2, "spring data jpa", true));
springClasses.add(new OnlineClass(3, "spring mvc", false));
springClasses.add(new OnlineClass(4, "spring core", false));
springClasses.add(new OnlineClass(5, "rest api development", false));
List<OnlineClass> javaClasses = new ArrayList<>();
javaClasses.add(new OnlineClass(6, "The Java, Test", true));
javaClasses.add(new OnlineClass(7, "The Java, Code mainpulation", true));
javaClasses.add(new OnlineClass(8, "The Java 8 to 11", false));
List<List<OnlineClass>> keesunEvents = new ArrayList<>();
keesunEvents.add(springClasses);
keesunEvents.add(javaClasses);
System.out.println("spring์ผ๋ก ์์ํ๋ ์์
");
springClasses.stream()
.filter(oc -> oc.getTitle().startsWith("spring"))
.forEach(System.out::println);
System.out.println("closed๋์ง ์์ ์์
");
springClasses.stream()
.filter(Predicate.not(OnlineClass::isClosed))
.forEach(System.out::println);
System.out.println("์์
์ด๋ฆ๋ง ๋ชจ์์ ์คํธ๋ฆผ ๋ง๋ค๊ธฐ");
Stream<String> springTitleStream = springClasses.stream()
.map(OnlineClass::getTitle);
springTitleStream.forEach(System.out::println);
System.out.println("๋ ์์
๋ชฉ๋ก์ ๋ค์ด์๋ ๋ชจ๋ ์์
์์ด๋ ์ถ๋ ฅ");
keesunEvents.stream()
.flatMap(Collection::stream)
.forEach(oc-> System.out.println(oc.getId()));
System.out.println("10๋ถํฐ 1์ฉ ์ฆ๊ฐํ๋ ๋ฌด์ ํ ์คํธ๋ฆผ ์ค์์ ์์ 10๊ฐ ๋นผ๊ณ ์ต๋ 10๊ฐ ๊น์ง๋ง");
Stream.iterate(10, i -> i+1)
.skip(10)
.limit(10)
.forEach(System.out::println);
System.out.println("์๋ฐ ์์
์ค์ Test๊ฐ ๋ค์ด์๋ ์์
์ด ์๋์ง ํ์ธ");
boolean test = javaClasses.stream().
anyMatch(oc -> oc.getTitle().contains("Test"));
System.out.println(test);
System.out.println("์คํ๋ง ์์
์ค์ ์ ๋ชฉ์ด spring์ด ๋ค์ด๊ฐ ์ ๋ชฉ๋ง ๋ชจ์์ List๋ก ๋ง๋ค๊ธฐ");
List<String> spring = springClasses.stream()
.filter(oc -> oc.getTitle().contains("spring"))
.map(OnlineClass::getTitle)
.collect(Collectors.toList());
spring.forEach(System.out::println);
}
# Reference
โ ์ธํฐํ์ด์ค์ ๋ณํ Optional โ