Stream API
์ปฌ๋ ์ (๋ฐฐ์ด ํฌํจ) ์ ์ ์ฅ ์์๋ฅผ ํ๋์ฉ ์ฐธ์กฐํด์ ํจ์ํ ์คํ์ผ์ ๋๋ค์์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋๋ก ํด์ฃผ๋ ๋ฐ๋ณต์
์๋ฐ 8๋ถํฐ ์๊ธด API์ด๋ค. ์ปฌ๋ ์ ์ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ๊ณ ์์๋ค์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ๋ฉฐ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ปฌ๋ ์ ์ผ๋ก ๋ชจ์์ฃผ๋ ์ญํ ์ ํ๋ค.
ํน์ง
๋๋ค์์ผ๋ก ์์ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋ค.
์คํธ๋ฆผ์์ ์ ๊ณตํ๋ ์์ ์ฒ๋ฆฌ ๋ฉ์๋๋ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ๋งค๊ฐ ํ์ ์ผ๋ก ๋ฐ๊ณ ์๋ค. ๋ฐ๋ผ์ ๋๋ค์์ด๋ ๋ฉ์๋ ์ฐธ์กฐ๋ฅผ ์ด์ฉํ ์์ ์ฒ๋ฆฌ ๋ด์ฉ์ ๋งค๊ฐ๊ฐ์ ์ ๋ฌํ ์ ์๋ค.
c.f. ํจ์ํ ์ธํฐํ์ด์ค
์ถ์ ๋ฉ์๋๊ฐ ๋ฑ ํ๊ฐ์ธ ์ธํฐํ์ด์ค. default ๋ฉ์๋๋ static ๋ฉ์๋๋ ์ฌ๋ฌ ๊ฐ ์์ด๋ ๊ด์ฐฎ๋ค.
์๋ฐ์์๋ @FunctionalInterface
์ด๋
ธํ
์ด์
์ ์ ๊ณตํ๋๋ฐ ์ด ์ด๋
ธํ
์ด์
์ ๋ถ์ธ ์ธํฐํ์ด์ค๋ ํจ์ํ ์ธํฐํ์ด์ค์ฌ์ผ ํ๋ค. ๋ ๊ฐ ์ด์์ ์ถ์ ๋ฉ์๋๊ฐ ์ ์ธ๋์ด ์์ผ๋ฉด ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค. ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋๋๋ฐ ์์ด ์ด ์ด๋
ธํ
์ด์
์ด ํ์๋ ์๋์ง๋ง ์ธํฐํ์ด์ค ๊ฒ์ฆ๊ณผ ์ ์ง๋ณด์ ์ธก๋ฉด์์ ์ฅ์ ์ด ์๋ค.
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
์ ์ธํ ์ฝ๋
์คํธ๋ฆผ์ ์ฌ์ฉํ๋ฉด how ๋ณด๋ค what์ ์ง์คํ ์ ์๋ค. 100๊ฐ์ ์ซ์๊ฐ ๋ค์ด์๋ ๋ฆฌ์คํธ์์ ํฌ๊ธฐ๊ฐ 50 ์ด์์ธ ์ซ์๋ง ๊ณจ๋ผ๋ด๋ ๋ ์ฝ๋๋ฅผ ๋น๊ตํด๋ณด์.
public List<Integer> filter50Above(List<Integer> list) {
List<Integer> result = new ArrayList<>();
for (Integer integer : list) {
if (integer >= 50) {
result.add(integer);
}
}
return result;
}
public List<Integer> filter50AboveStream(List<Integer> list) {
return list.stream()
.filter(integer -> integer >= 50)
.collect(Collectors.toList());
}
๋จ์ํ ๋น๊ต๋ ์ด๋ ต์ง๋ง ์คํธ๋ฆผ์ ์ฌ์ฉํ ๊ตฌํ์ด ๋ ๊ฐ๊ฒฐํด ๋ณด์ธ๋ค.
๋ด๋ถ ๋ฐ๋ณต
์คํธ๋ฆผ์ ๋ด๋ถ ๋ฐ๋ณต ๋ฐฉ์์ ์ฌ์ฉํ๋ค.
c.f. ์ธ๋ถ ๋ฐ๋ณต์, ๋ด๋ถ ๋ฐ๋ณต์
์ธ๋ถ ๋ฐ๋ณต์๋ ๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ก ์ง์ ์ปฌ๋ ์ ์ ์์๋ฅผ ๋ฐ๋ณตํด์ ๊ฐ์ ธ์ค๋ ์ฝ๋์ด๋ค. for-each ๋ฌธ, while๋ฌธ, Iterator ๋ฑ์ด ์ธ๋ถ ๋ฐ๋ณต์์ ์ํ๋ค.
๋ฐ๋ฉด ๋ด๋ถ ๋ฐ๋ณต์๋ ์ฒ๋ฆฌํด์ผ ํ ์ฝ๋๋ง ์ ๊ณตํ๊ณ ์ค์ ๋ฐ๋ณต์ ์ปฌ๋ ์ ๋ด๋ถ์์ ์์์ ์ฒ๋ฆฌ๋๋ ๋ฐฉ์์ด๋ค.

๋ด๋ถ ๋ฐ๋ณต์๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ป๊ฒ ์์๋ฅผ ๋ฐ๋ณต์ํฌ ๊ฒ์ธ์ง๋ ์ปฌ๋ ์ ์๊ฒ ๋งก๊ธฐ๊ณ ๊ฐ๋ฐ์ ์ ์ฅ์์๋ ์์ ์ฒ๋ฆฌ ์ฝ๋์๋ง ์ง์คํ ์ ์๋ค. ๋ด๋ถ ๋ฐ๋ณต์๋ ์์์ ๋ฐ๋ณต ์์๋ฅผ ๋ณ๊ฒฝํ๊ฑฐ๋ CPU ์ฝ์ด์๊ฒ ์์๋ฅผ ๋ถ๋ฐฐ์์ผ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋๋ก ๋์์ค๋ค.
์คํธ๋ฆผ ์ฒ๋ฆฌ
์คํธ๋ฆผ์ ์ปฌ๋ ์ ์ ์์์ ๋ํด ์ค๊ฐ ์ฒ๋ฆฌ์ ์ต์ข ์ฒ๋ฆฌ๋ฅผ ์ํํ๋ค. ์ค๊ฐ ์ฒ๋ฆฌ์๋ ๋งต, ํํฐ, ์ ๋ ฌ, ๋ฆฌ๋ฐ ๋ฑ์ด ์ํ๊ณ ์ต์ข ์ฒ๋ฆฌ์๋ ๋ฐ๋ณต, ์นด์ดํ , ์ง๊ณ์ฒ๋ฆฌ ๋ฑ์ด ์ํ๋ค.
์คํธ๋ฆผ์ ์ค๊ฐ ์ฒ๋ฆฌ์ ์ต์ข ์ฒ๋ฆฌ๋ฅผ ํ์ดํ๋ผ์ธ์ผ๋ก ํด๊ฒฐํ๋ค. ์ฆ ์ฌ๋ฌ ๊ฐ์ ์คํธ๋ฆผ์ด ํ์ดํ๋ผ์ธ์ผ๋ก ์ฐ๊ฒฐ๋์ด ์๋ค. ์ค๊ฐ ์ฒ๋ฆฌ ์คํธ๋ฆผ ํจ์๋ค์ ๋ฆฌํด ๊ฐ์ผ๋ก ์๋ก์ด ์คํธ๋ฆผ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์คํธ๋ฆผ ํจ์๋ค์ ์ฒด์ด๋ (chaining) ํ ์ ์๊ณ ์ด ๊ณผ์ ์ ํ์ดํ๋ผ์ธ ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์ค๊ฐ ์ฒ๋ฆฌ ์คํธ๋ฆผ์ ์์ฑ๋๋ ์์ ์ ๋ฐ๋ก ์ค๊ฐ ์ฒ๋ฆฌ (๋งคํ, ํํฐ๋ง, ์ ๋ ฌ ๋ฑ) ๋๋ ๊ฒ์ด ์๋๊ณ ์ต์ข ์ฒ๋ฆฌ๊ฐ ์์๋๊ธฐ ์ ๊น์ง ์ง์ฐ๋๋ค. ์ต์ข ์ฒ๋ฆฌ๊ฐ ์์๋ ๋ ๋น๋ก์ ์ปฌ๋ ์ ์ ์์๊ฐ ํ๋์ฉ ์ค๊ฐ ์คํธ๋ฆผ์์ ์ฒ๋ฆฌ๋๋ค.
์ด๋ฅผ Lazy Evaluation ์ด๋ผ๊ณ ๋งํ๋ค. ์ฃผ์ด์ง ์ฝ๋๋ฅผ ๋ฐ๋ก ์คํํ๋๊ฒ์ด ์๋๋ผ ๊ฒฐ๊ณผ๊ฐ์ด ํ์ํ ๋ ๊น์ง ๊ณ์ฐ์ ๋ฆ์ถ์ด ๋ถํ์ํ ์ฐ์ฐ์ ํผํ ์ ์๋ค. ๋ค๋ง JVM์ด ๋ด๋ถ์ ์ผ๋ก ์ง์ฐ ์ฐ์ฐ์ ์ํ ์ค๋น ์์ ์ ์ํํ๊ธฐ ๋๋ฌธ์ ๋ฌด์กฐ๊ฑด ์ฑ๋ฅ์ด ์ข๋ค๊ณ ๋จ์ ํ ์๋ ์๋ค.
์ฐธ๊ณ : https://bugoverdose.github.io/development/stream-lazy-evaluation/
์ฌ์ฉ๋ฒ
์ค๊ฐ ์ฒ๋ฆฌ ๋ฉ์๋์ ์ต์ข ์ฒ๋ฆฌ ๋ฉ์๋์ ๊ตฌ๋ถ์ ๋ฆฌํด ํ์ ์ผ๋ก ์ ์ ์๋ค. ๋ฆฌํด ํ์ ์ด Stream์ธ ๋ฉ์๋ ๋ค์ด ์ค๊ฐ ์ฒ๋ฆฌ ๋ฉ์๋์ด๋ค.
์ค๊ฐ ์ฒ๋ฆฌ ๋ฉ์๋

์ต์ข
์ฒ๋ฆฌ ๋ฉ์๋

์คํธ๋ฆผ ๋ณ๋ ฌ ์ฒ๋ฆฌ
๋ฉํฐ ์ฝ์ด CPU ํ๊ฒฝ์์ ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ์ชผ๊ฐ์ด ์๋ธ ๋ฐ์ดํฐ๋ก ๋ง๋ค๊ณ ๊ฐ๊ฐ์ ์ฝ์ด์์ ๋ณ๋ ฌ์ ์ผ๋ก ์ฒ๋ฆฌํ๋๊ฒ์ ๋งํ๋ค. ํ๋์ CPU ์ฝ์ด ์์์ ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋๊ฐ ์คํ๋๋ ๋์์ฑ (Concurrency)๊ณผ ๊ตฌ๋ถ๋๋ค.
์๋ฐ ๋ณ๋ ฌ ์คํธ๋ฆผ์ CPU ์ฝ์ด์ ์ ๋งํผ ๋ฐ์ดํฐ๋ฅผ ๋๋๊ณ ๊ฐ๊ฐ์ ์๋ธ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฆฌ๋ ์ค๋ ๋์์ ๋ณ๋ ฌ ์ฒ๋ฆฌํ๋ค. ์ฟผ๋์ฝ์ด CPU์ ๊ฒฝ์ฐ ์๋ธ ๋ฐ์ดํฐ๋ 4๊ฐ๊ฐ ์์ฑ๋๊ณ 4๊ฐ์ ์ค๋ ๋์์ ๋ณ๋ ฌ๋ก ์คํํ๋ค.
์ฑ๋ฅ
ํ๋์ ์ฝ์ด์์ ์คํ๋๋ ์์ฐจ ์ฒ๋ฆฌ๋ณด๋ค ๋ณ๋ ฌ ์ฒ๋ฆฌ๊ฐ ๋น ๋ฅด๋ค๊ณ ๋ณด์ฅํ ์ ์๋ค. ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ ๋ด๋ถ์ ์ผ๋ก ์ค๋ ๋ํ์ ์์ฑํ๊ณ ์ค๋ ๋๋ฅผ ๋ง๋๋ ์ค๋ฒํค๋๊ฐ ๋ฐ๋ผ์ค๊ธฐ ๋๋ฌธ์ด๋ค. ์ปฌ๋ ์ ์ ์์๊ฐ ์ ๊ณ ์์๋น ์ฒ๋ฆฌ ์๊ฐ์ด ์งง์ผ๋ฉด ์์ฐจ ์ฒ๋ฆฌ๊ฐ ๋ ๋น ๋ฅผ ์ ์๋ค.
์คํธ๋ฆผ ํจ์ํ ์ธํฐํ์ด์ค ์ข
๋ฅ
์คํธ๋ฆผ์ ์ฌ์ฉํ ๋ ์์ฃผ ์ฌ์ฉ๋๋ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ์์๋ณด์.
Predicate
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
์ธ์ ํ๋๋ฅผ ๋ฐ์์ boolean ํ์ ์ ๋ฆฌํดํ๋ค.
filter, allMatch, anyMatch ๋ฉ์๋ ๋ฑ์ ์ธ์๋ก ์ฐ์ธ๋ค.
Consumer
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
์ธ์ ํ๋๋ฅผ ๋ฐ์์ ์๋ฌด๊ฒ๋ ๋ฆฌํดํ์ง ์๋๋ค. Consumer (์๋น์) ๋ผ๋ ์ด๋ฆ์ ๊ฑธ๋ง๊ฒ ์ธ์ ํ๋๋ฅผ ๋ฐ์ ์๋น๋ง ํ๊ณ ๋๋ธ๋ค.
forEach, peek ๋ฉ์๋ ๋ฑ์ ์ธ์๋ก ์ฐ์ธ๋ค.
Function
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
์ธ์ ํ๋๋ฅผ ๋ฐ์์ R ํ์
์ ๋ฆฌํดํ๋ค. R ํ์
์ด int, double, long์ผ๋ก ๊ณ ์ ๋์ด์๋ ToXXXFunction<T>
์ธํฐํ์ด์ค๋ ์๋ค.
map, flatMap ๋ฉ์๋ ๋ฑ์ ์ธ์๋ก ์ฐ์ธ๋ค.
c.f. mapToInt, mapToLong, mapToDouble ์์๋ ๊ฐ์์ ๋ง๋ ToXXXFunction์ ์ธ์๋ก ์ฌ์ฉํ๋ค.
Supplier
@FunctionalInterface
public interface Supplier<T> {
T get();
}
์ธ์๋ฅผ ๋ฐ์ง ์๊ณ T ํ์ ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ค. Supplier (๊ณต๊ธ์) ๋ผ๋ ์ด๋ฆ์ ๊ฑธ๋ง๊ฒ ์๋ฌด ์ธ์๋ ๋ฐ์ง ์๊ณ ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ค.
collect ๋ฉ์๋์ ์ธ์๋ก ์ฐ์ธ๋ค.
์ด์ธ์๋ reduce์ ์ธ์๋ก ์ฐ์ด๋ BinaryOperator, sorted์ ์ธ์๋ก ์ฐ์ด๋ Comparator ๋ฑ ๋ค์ํ ํจ์ํ ์ธํฐํ์ด์ค๊ฐ ์๋ค.
ํจ์ํ ์ธํฐํ์ด์ค ์ฌ์ฉ
์ง์ ๊ตฌํ
public class MyImpl implements Predicate<Integer> {
@Override
public boolean test(Integer integer) {
return integer >= 50;
}
}
MyImpl predicate = new MyImpl();
List<Integer> result = integers.stream()
.filter(predicate)
.collect(Collectors.toList());
์ต๋ช
ํด๋์ค ์ฌ์ฉ
List<Integer> result = integers.stream()
.filter(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer >= 50;
}
})
.collect(Collectors.toList());
๋๋ค์ ์ฌ์ฉ
List<Integer> result = integers.stream()
.filter(integer -> integer >= 50)
.collect(Collectors.toList());
Last updated