반응형

📝Stream

Java8에서 나온 것으로 매개변수들이 함수형 인터페이스 기반으로 만들어져 Stream에서 쓰는 내부 함수들은 Predicate, Function처럼 함수형 인터페이스를 사용한다

// Stream 인터페이스 내부 함수
Stream<T> filter(Predicate<? super T> predicate);
<R> Stream<R> map(Function<? super T, ? extends R> mapper);

Stream 장점으로는 Lazy Evaluation으로 이 의미는 즉, 불필요한 연산을 피한다는 의미이다.

배열의 값을 하나씩 읽어서 순차적으로 진행시킨다.  밑에 코드에서 보는 것 처럼 i < 6이라는 조건절이 있는 경우 1 ~ 10까지 i < 6처리한 후에 남은 애들이 2번째  조건 절인 i % 2 == 0을 거치는게 아니라 "1"이 i < 6을 거친 후 i % 2 == 0을 거치는 순차적인 Iterator로 돌아가게 된다.

 

Stream 동작 트래킹

@Test
public void test(){
    final List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

    System.out.println(
        list.stream()
            .filter(i -> {
                System.out.println(i + " : i < 6");
                return i<6;
            })
            .filter(i -> {
                System.out.println(i + " : i % 2 == 0");
                return i%2==0;
            })
            .collect(Collectors.toList())
    );
    /**
     * 1 : i < 6
     * 1 : i % 2 == 0
     * 2 : i < 6
     * 2 : i % 2 == 0
     * 3 : i < 6
     * 3 : i % 2 == 0
     * 4 : i < 6
     * 4 : i % 2 == 0
     * 5 : i < 6
     * 5 : i % 2 == 0
     * 6 : i < 6
     * 7 : i < 6
     * 8 : i < 6
     * 9 : i < 6
     * 10 : i < 6
     * [2, 4]
     */
}

 

여기서 예제를 보면 1 ~ 10을 1번 필터를 다 거친 후 남은 걸 2번 필터를 거치거나 각 Iterator들을 개별로 1번 → 2번을 거치거나 별 차이는 없어보인다 하지만 밑에 같은 예제의 경우 이야기가 달라진다. findFirst로 1개의 정상 값만 나오면 바로 종료시켜버린다 물론 IF로직같은 걸로 1개 일 때 종료하던가 로직 처리가 가능하지만 가독성 및 효율성이 떨어진다.

 

Stream 동작 트래킹

@Test
public void test(){
    final List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

    System.out.println(
        list.stream()
            .filter(i -> {
                System.out.println(i + " : i < 6");
                return i<6;
            })
            .filter(i -> {
                System.out.println(i + " : i % 2 == 0");
                return i%2==0;
            })
            .findFirst()
    );
    /**
     * 1 : i < 6
     * 1 : i % 2 == 0
     * 2 : i < 6
     * 2 : i % 2 == 0
     */
}

 

동작 방식을 이제 알아봤으니 이걸 이용해 익숙해져보자

 

Stream 사용해보기

package hello.exception;

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

public class StreamTest {

    @Test
    public void intStreamTest(){

        /** ---- 연속적인 값 할당 ---- **/
        IntStream.range(0, 10).forEach(i -> System.out.println("range : " + i)); // range : 0 range : 1 .... range : 9
        // IntStream.iterate(1, i -> i + 1).forEach(i -> System.out.println("iterate : " + i)); // iterate : 1 ... iterate : 21
        IntStream.rangeClosed(0, 10).forEach(i -> System.out.println("rangeClose : " + i)); // rangeClose : 0 rangeClose : 1 ... rangeClose : 10

        /** ---- Sum ---- **/
        long sum = IntStream.of(1, 2, 3, 4, 5)
                .sum();

        System.out.println("sum : " + sum); // sum : 15

    }

    @Test
    public void streamTest(){

        /** ---- of, forEach ---- **/
        Stream.of(1, 2, 3, 4, 5)
                .forEach(i -> System.out.println("stream of : " + 1)); // stream of : 1 ... stream of : 5

    }

    @Test
    public void streamChaningTest(){

        /** ---- stream chaning ---- **/
        final List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Optional<Integer> result =
                numbers.stream() // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
                        .filter(number -> number > 3) // 4, 5, 6, 7, 8, 9, 10
                        .filter(number -> number < 9) // 4, 5, 6, 7, 8
                        .map(number -> number * 2)    // 8, 10, 12, 14, 16
                        .filter(number -> number < 15) // 8, 10, 12, 14
                        .findAny(); // 8

        System.out.println("stream result : " + result.get());


        // Intermediate Operation Method [Stream 리턴 -> chaning 가능]
        // Terminated Operation Method   [Stream 외 리턴]
    }
    @Test
    public void streamChaningTest2(){

        final List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        /** ---- collection(toList()) ---- **/
        List<String> result = numbers.stream()
                .filter(number -> number > 8) // 9, 10
                .map(number -> "#" + number)
                .collect(toList());

        System.out.println("result : " + result); // result : [#9, #10]

        /** ---- collection(joining) ---- **/
        String result2 = numbers.stream() // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
                .filter(number -> number > 8) // 4, 5, 6, 7, 8, 9, 10
                .map(number -> "#" + number)
                .collect(joining(",","[","]"));

        System.out.println("result2 : " + result2); // result2 : [#9,#10]

        /** ---- collection(toSet()) ---- **/
        Set<String> result3 = numbers.stream() // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
                .filter(number -> number > 8) // 4, 5, 6, 7, 8, 9, 10
                .map(number -> "#" + number)
                .collect(toSet());

        System.out.println("result3 : " + result3); // result3 : [#10, #9]

        /** ---- distinct ---- **/
        List<String> result4 =
                Stream.of(1, 3, 3, 5, 5)
                        .filter(number -> number > 2)
                        .map(number -> number * 2)
                        .map (number -> "#" + number) // [#6, #6, #10, #10]
                        .distinct()                   // [#6, #10]
                        .collect(toList());

        System.out.println("result4 : " + result4); // result4 : [#6, #10]

        /** —— count —— **/
        long result5 =
                Stream.of(1, 3, 3, 5, 5)
                        .filter(number -> number > 2)
                        .map(number -> number * 2)
                        .map (number -> "#" + number) // [#6, #6, #10, #10]
                        .distinct()                   // [#6, #10]
                        .count();

        System.out.println("result5 : " + result5); // result5 : 2

    }
    
	@Test
    public void reduceTest(){
        /** —— reduce —— **/
        List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer result =
                numbers.stream()
                        .reduce(100, (x, y) -> {
                            System.out.println("x : " + x + ", y :" + y);
                            return x+y;
                        });

        // reduce : 반복된 패턴을 추상화 할 수 있다.
        System.out.println("result : " + result);

        /**
         * x : 100, y :1
         * x : 101, y :2
         * x : 103, y :3
         * x : 106, y :4
         * x : 110, y :5
         * x : 115, y :6
         * x : 121, y :7
         * x : 128, y :8
         * x : 136, y :9
         * x : 145, y :10
         * result : 155
         */

    }

}

 

 

 

🔗 참고 및 출처

https://dororongju.tistory.com/137

반응형