Stream

๊น€์•„๋ฌด๊ฐœยท2023๋…„ 5์›” 14์ผ
0

Java

๋ชฉ๋ก ๋ณด๊ธฐ
14/23

์ŠคํŠธ๋ฆผ์ด๋ž€?

๋ฐฐ์—ด, ์ปฌ๋ ‰์…˜ ๋Œ€์ƒ์œผ๋กœ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰

์ปฌ๋ ‰์…˜์€ ๊ธฐ๋ณธ์œผ๋กœ stream()์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐฐ์—ด์€ Arrays ์ด์šฉ!

์ผ๊ด€์„ฑ ์žˆ๋Š” ์—ฐ์‚ฐ์œผ๋กœ ์ž๋ฃŒ์˜ ์ฒ˜๋ฆฌ๋ฅผ ์‰ฝ๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•œ๋‹ค.

์ž๋ฃŒ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ์ถ”์ƒํ™”๊ฐ€ ๊ตฌํ˜„๋˜์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค.

ํ•œ๋ฒˆ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•œ ์ŠคํŠธ๋ฆผ์€ ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜ ์—†์Œ

์ŠคํŠธ๋ฆผ ์—ฐ์‚ฐ์€ ๊ธฐ์กด ์ž๋ฃŒ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ž๋ฃŒ์— ๋Œ€ํ•œ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•˜๋ฉด ์ŠคํŠธ๋ฆผ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์€ ๋ณ„๋„๋กœ ์ƒ์„ฑ๋˜๋ฏ€๋กœ

์—ฐ์‚ฐ์ด ์ˆ˜ํ–‰๋˜๋„ ๊ธฐ์กด ์ž๋ฃŒ์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ์€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ŠคํŠธ๋ฆผ ์—ฐ์‚ฐ์€ ์ค‘๊ฐ„ ์—ฐ์‚ฐ๊ณผ ์ตœ์ข… ์—ฐ์‚ฐ์œผ๋กœ ๊ตฌ๋ถ„๋œ๋‹ค.

์ค‘๊ฐ„ ์—ฐ์‚ฐ์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์—ฐ์‚ฐ์ด ์ ์šฉ๋  ์ˆ˜ ์žˆ์ง€๋งŒ,

๋งˆ์ง€๋ง‰ ์—ฐ์‚ฐ์€ ๋‹จ ํ•˜๋‚˜๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ตœ์ข… ์—ฐ์‚ฐ์ด ํ˜ธ์ถœ๋˜์–ด์•ผ ์ค‘๊ฐ„ ์—ฐ์‚ฐ์— ๋Œ€ํ•œ ์ˆ˜ํ–‰์ด ์ด๋ฃจ์–ด ์ง€๊ณ  , ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.

์ด๋Ÿฐ ์—ฐ์‚ฐ์„ ์ง€์—ฐ ์—ฐ์‚ฐ์ด๋ผ๊ณ  ํ•˜๋Š”๋ฐ,

lazy init๋„ ํ•„์š”์‹œ ํ˜ธ์ถœ์— ์˜ํ•ด ์ดˆ๊ธฐํ™” ๋˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ

์ŠคํŠธ๋ฆผ๋„ ๋งˆ์ง€๋ง‰ ์—ฐ์‚ฐ์‹œ ์ค‘๊ฐ„ ์—ฐ์‚ฐ์„ ํ˜ธ์ถœํ•˜๋Š” lazy ์—ฐ์‚ฐ์ด๋‹ค.

๋งˆ์ง€๋ง‰ ์—ฐ์‚ฐ์„ ํ•˜์ง€ ์•Š์œผ๋ฉด ์ค‘๊ฐ„ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.


IntStream

int[] -> IntStream

int๋ฐฐ์—ด์„ IntStream์œผ๋กœ ๋ณ€๊ฒฝ ํ•ด๋ณด๋Š” ์ž‘์—…

int[] arr = {1, 2, 3, 4, 5};

for (int num : arr) {
    System.out.println(num); 
}
// ์ถœ๋ ฅ 
// 1
// 2
// 3
// 4
// 5
IntStream is = Arrays.stream(arr);
is.forEach(System.out::println); // is๊ฐ€ ์—ฌ๊ธฐ์„œ ์†Œ๋ชจ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€
// ์ถœ๋ ฅ 
// 1
// 2
// 3
// 4
// 5

Arrays.stream(int[] arr)๋Š” IntStream์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
foreach()๋Š” Consumer ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ธ์ž๋กœ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์—, ๋ฐ˜ํ™˜๊ฐ’์ด ์—†๋‹ค.
( void Consumer<T> )

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— System.out::println์„ ์ž‘์„ฑํ•ด์ฃผ๋ฉด
foreach()๋กœ ๊ฐ’์ด ๋“ค์–ด์˜ฌ๋•Œ ๋งˆ๋‹ค ๋ฐ”๋กœ ์ถœ๋ ฅํ•œ๋‹ค.

์ฐธ๊ณ ๋กœ System.out::println ์€
Consumer ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์„ ๋žŒ๋‹ค์‹์œผ๋กœ ํ‘œํ˜„ํ•œ n -> System.out.println(n) ์„
๋ฉ”์„œ๋“œ ์ฐธ์กฐํ˜• ๋ฌธ๋ฒ•์œผ๋กœ ๋ณ€ํ™˜ํ•œ ํ˜•ํƒœ์ด๋‹ค.

Arrays.stream(arr).forEach(System.out::println);

๋ณดํ†ต ์ด๋Ÿฐ ํ˜•ํƒœ๋กœ ์“ฐ์ธ๋‹ค.

์ค‘๊ฐ„ ์—ฐ์‚ฐ์ž

์ž˜ ์“ฐ์ด๋Š” ์ค‘๊ฐ„์—ฐ์‚ฐ์ž ๋ช‡๊ฐœ๋งŒ ์‚ดํŽด๋ณด๊ณ  ๋„˜์–ด๊ฐ„๋‹ค.
์ค‘๊ฐ„ ์—ฐ์‚ฐ์ž๋Š” ๋„ˆ๋ฌด ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— stream ์‚ฌ์šฉ์‹œ ctrl + space์˜ ๋„์›€์„ ๋ฐ›์•„
๊ทธ๋•Œ ๊ทธ๋•Œ ํ•„์š”ํ•œ ์—ฐ์‚ฐ์ž๋ฅผ ๊ณจ๋ผ์„œ ์‚ฌ์šฉํ•  ์ค„ ์•„๋Š” ๊ฒƒ๋„ ํ•„์š”ํ•˜๋‹ค๊ณ  ๋ฐฐ์›€!

filter


filter๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ Predicate<T, boolean>์„ ๋ฐ›๋Š”๋‹ค.
Predicate๋Š” T๋ฅผ ๋ฐ›์•„์„œ boolean์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค!

๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์˜ˆ์‹œ

private static long count(int[] arr) {
    // 2๋ณด๋‹ค ํฐ ์ˆ˜๋งŒ ์นด์šดํŠธ

    // boolean filter(Predicate<T>)
    return Arrays.stream(arr)
            .filter(n -> n > 2)
            .count();
}

map

map์€ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ UnaryOperator<T>๋ฅผ ๋ฐ›๋Š”๋‹ค.
UnaryOperator๋Š” T๋ฅผ ๋ฐ›์•„์„œ T๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ํด๋ž˜์Šค!

๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์˜ˆ์‹œ

private static long sum2(int[] arr) {
    // map์œผ๋กœ ๋ฐฐ์—ด ์š”์†Œ๋“ค ๊ฐ๊ฐ์— 2๋ฅผ ๊ณฑํ•ด์„œ ๋ฐ˜ํ™˜ ํ›„ sum() ์—ฐ์‚ฐ

    // T map(UnaryOperator<T>) ์˜คํ˜ธ ํ‹ฐ๋งต
    return Arrays.stream(arr)
            .map(n -> n * 2)
            .sum();
}

boxed()

๊ธฐ๋ณธ ์ž๋ฃŒํ˜•์„ ๊ทธ์— ํ•ด๋‹นํ•˜๋Š” wrapper ํด๋ž˜์Šค๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• 

Ex : intStream -> Stream<Integer>

IntStream intStream = IntStream.range(1, 5);
Stream<Integer> integerStream = intStream.boxed();

sorted()

๊ธฐ๋ณธ์ž๋ฃŒํ˜• ๋ฐฐ์—ด๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด
์ธ์ž ์—†์ด ์‚ฌ์šฉํ•˜์—ฌ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ๋งŒ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

IntStream sorted();

wrapper ํด๋ž˜์Šค ๋ฐฐ์—ด๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด
Comparator๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ •์˜ ์˜ค๋ฆ„์ฐจ์ˆœ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

Stream<T> sorted( Comparator<? super T> comparator )



ArrayList ๊ฐ์ฒด์— ์ŠคํŠธ๋ฆผ ์ƒ์„ฑ/์‚ฌ์šฉ

ArrayList<String> ์„ stream์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ถœ๋ ฅํ•˜๊ธฐ 1

List<String> list = new ArrayList<>();
list.add("๋ฝ€๋กœ๋กœ");
list.add("๋ฃจํ”ผ");
list.add("์—๋””");

Stream<String> stream = list.stream();
stream.forEach(System.out::println);
// ๋ฝ€๋กœ๋กœ
// ๋ฃจํ”ผ
// ์—๋””

ArrayList<String> ์„ stream์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ถœ๋ ฅํ•˜๊ธฐ 2

List<String> list = new ArrayList<>();
list.add("๋ฝ€๋กœ๋กœ");
list.add("๋ฃจํ”ผ");
list.add("์—๋””");

Stream<String> stream = list.stream();
stream.sorted().forEach(System.out::println);
// ๋ฃจํ”ผ
// ๋ฝ€๋กœ๋กœ
// ์—๋””

map

private static void print3(List<String> list) {
	Stream<String> stream = list.stream();
	stream.map(s -> s.length())
	        .forEach(System.out::println);
}
// 3
// 2
// 2

filter

private static void print3(List<String> list) {
	Stream<String> stream = list.stream();
	stream.filter(s -> s.length() > 2)
	        .forEach(System.out::println);
}
// ๋ฝ€๋กœ๋กœ

reduce ์—ฐ์‚ฐ

reduce๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฐ์‚ฐ ์ˆ˜ํ–‰์— ๋Œ€ํ•œ ๊ตฌํ˜„์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
์˜ค, reduce ์ž˜ ์“ฐ๋ฉด ์ด๊ฑธ๋กœ ์™ ๋งŒํ•œ๊ฑด ์ „๋ถ€ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์žˆ์„์ง€๋„...!!

์ธ์ž๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค 1

BiFunction<U, ? super String, U>

public interface BiFunction<T, U, R> {
    R apply(T, U);
}

๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์˜ˆ์‹œ

BiFunction<Integer, Integer, String> sum = (a, b) -> String.valueOf(a + b);
System.out.println( sum.apply(2, 3) );  // 5

์ธ์ž๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค 2

BinaryOperator<String>
BiFunction<T, T, T>์˜ ํŠน์ˆ˜ํ•œ ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์–ด์ง„ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.

public interface BinaryOperator<T> extends BiFunction<T, T, T> {
    @Override
    T apply(T, T);
}

๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์˜ˆ์‹œ

BinaryOperator<String> bo = (s, s2) -> s.length() >= s2.length() ? s : s2;
System.out.println( bo.apply(str1, str2) );

reduce ๊ฐ„๋‹จ ์‚ฌ์šฉ ์˜ˆ์‹œ

public class reduceStudy {
    public static void main(String[] args) {
        String[] arr = {"์•ˆ๋…•ํ•˜์„ธ์š”!", "Hi!", "Hi~~~", "Hello!", "Hello~~~", "์•ˆ๋…•ํ•˜์„ธ์š” ^^"};

        System.out.println( print(arr) );
    }

    private static String print(String[] arr) {
        return Arrays
                .stream( arr )
                .reduce(
                        "์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’",
                        (s1, s2) -> s1.length() >= s2.length() ? s1 : s2
                );
    }
}

print()์—์„œ ์‚ฌ์šฉ ๋œ reduce()๋ฅผ ๋ณด๋ฉด , ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ 2๊ฐœ ๋„˜๊ฒจ์ฃผ๊ณ  ์žˆ๋Š”๋ฐ,
์ฒซ๋ฒˆ์งธ๋กœ ๋„˜์–ด๊ฐ„ ๊ฐ’์€ U u ํƒ€์ž…์ด๊ณ , ๋‘๋ฒˆ์งธ๋กœ ๋„˜์–ด๊ฐ„ ๊ฐ’์€ T BinaryOperator<T> ํƒ€์ž…์ด๋‹ค.

๋‘๋ฒˆ์งธ๋กœ ๋„˜์–ด๊ฐ„ ๊ฐ’์ด
์ฒซ๋ฒˆ์งธ๋กœ ๋„˜์–ด๊ฐ„ ๊ฐ’ ๋ณด๋‹ค ๊ธธ์ด๊ฐ€ ๊ธธ์–ด์•ผ ๋ฐ˜ํ™˜๋œ๋‹ค.

์ฒซ๋ฒˆ์งธ๋กœ ๋„˜์–ด๊ฐ„ ๊ฐ’ ๋ณด๋‹ค ๊ธธ์ด๊ฐ€ ์งง์œผ๋ฉด ์ฒซ๋ฒˆ์งธ ์ธ์ž๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.

๊ทธ๋ž˜์„œ ์œ„์˜ ์˜ˆ์‹œ ๊ฒฐ๊ณผ๋Š” ์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’์ดˆ๊ธฐ๊ฐ’ ์ด๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€