ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 람다 2편)람다의 활용, stream API
    Java 2023. 9. 22. 11:10

    지난글에서 함수형 인터페이스들을 통해 람다식이 실행될 수 있음을 알아보았다. 

    이번 글에서는 람다식을 많이 활용하는 stream 기능에 대해 알아보려한다.

     

    list.stream().forEach((k)->{  //forEach는 매개변수만 있으면 됨.
        System.out.println(5);
    });

    간단한 stream 예시문이다.  stream은 for문 매우 흡사하다. 각각 하나의 요소들을 탐색하고, 요소들에 어떤 작업을 한다.

     

    그럼 왜 for문이 기존에 있는데 굳이 stream을 쓰는지?

    답은 람다식을 쓰는 이유와 같이 가독성에 있다. 

     

     

    리스트에 1234 요소가 있다면 Exception을 터트리는 예제다. 

     

    for문과 if문을 사용한다면 위처럼 나뉘어져서 for문과 if문이 서로 어떤 연관이 있는지 쉽게 알아보기 어렵다.

    반면 stream (+optional)문은  한눈에 알아볼 수 있다. 


    stream을 왜 쓰는지 알아보았으니 이제 stream을 어떻게 쓸 수 있는지 알아보자.

     

     

     

    Map은 따라서 그냥 사용할수는 없고, 변환작업이 필요하다(뒤에서 설명)

    list.stream() ~ , set.stream() 과 같이 stream은 collection 타입에서 작동한다.

    Arrays.stream(배열).boxed().toList();

    그래서 일반 Array를 stream에서 사용하고싶다면 다음과 같은 작업이 필요한 것이다. 


    stream 의 API

     

    1. forEach()

    list.stream().forEach((k)->{  //forEach는 매개변수만 있으면 됨.
        System.out.println(k);
    });

    forEach()는 for문과 유사하다.

    하나의 요소를 작업하는 함수인데, 특이점은 void 타입이라 그 다음 단계에서는 stream api를 사용하지 못한다. 

     

    사실상 마지막에 print를 한다던가 , 더 이상 stream api를 사용하지 않을때 사용한다. 

     

    조심해야할 것은 forEach()내에는 로직을 구현하지 않는것이다.

     

           list.stream().forEach(k ->{
                    if (k == 1)
                        return;
                System.out.println(k);
            });  //결과: 2,3,4,5,6...

    다음 코드에서 리스트의 첫 요소인 1이 return되면서 모두 실행되지 않을 것 같지만,

    forEach는 강제로 모든 요소를 돌기때문에 우리가 생각하지 못한 결과가 나올 수 있다.

     

    그러니까 stream에서 forEach()를 쓰려면 결과값에서만 사용하도록 하자.

     

    2. filter()

    filter()는 이름그대로 필터링 기능이다. 

            list.stream().filter((k)->{
                if (k==10) 
                    throw new RuntimeException();
                return true;
            }).findAny().get(); //여기선10을 제외하고 뽑아냄

    기본문법은 true가 나오면 통과시키고, false가 나오면 통과하지 못하고 다음 stream요소로 넘어간다.

     

    for문+if문은 break를 통해 강제종료가 가능하지만,

    stream + filter를 통해  Exception을 터트려서 종료시켜야 한다. 

     

    3. map()

    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    List<Integer>list1 = list.stream().map( k ->k*10 ).toList();
    //list1 의 요소는 10,20,30

    map()은 기존 컬렉션의 값들을 가공해서 새로운 값을 만들어준다. 

     

    4. sorted()

    list.stream().sorted()

    컬렉션 타입을 정렬한다.

     

    5. collect()

    스트림의 컬렉션/배열 변환 작업을 한다. - toList(), toSet(), toMap(), toCollection, toArray()

     

    용어들이 조금 헷갈릴수 있는데,

    collect() 스트림의 최종연산, 매개변수로 컬렉터를 필요로 한다.
    Collector 인터페이스로 컬렉터는 이를 구현해야 한다.
    Collectors 클래스로 static 메서드로 미리 구현한 컬렉터를 제공한다.

    collect()는 stream에서 쓰는 메서드고, Collector는 collect()의 파라미터로 받을 인터페이스다.

            Set<Integer> collect = list.stream()
                    .collect(Collectors.toSet());

    Collectors는 기존에 자바에서 제공하는 클래스로, static메서드를 통해 쉽게 컬렉션을 바꿔줄 수 있다.

     


     

    Reference

    - https://hbase.tistory.com/171

    - https://abcdefgh123123.tistory.com/424

    - https://tecoble.techcourse.co.kr/post/2020-05-14-foreach-vs-forloop/

Designed by Tistory.