[Java] Stream (스트림) - 1

✨New Wisdom✨·2020년 12월 24일
2

📕 Java 📕

목록 보기
11/24
post-thumbnail

스트림

배열 또는 컬렉션 인스턴스에 저장된 데이터를 꺼내서 파이프에 흘려보낸다.

  • 중간 연산 : 마지막이 아닌 위치에서 진행이 되어야 하는 연산
  • 최종 연산 : 마지막에 진행이 되어야 하는 연산
    스트림은 중간 연산과 최종 연산을 진행하기 좋은 구조로 배치된 복사본이라 할 수 있다.
    k

스트림의 특성

class MyFirstStream2 {
    public static void main(String[] args) {
        int[] ar = {1, 2, 3, 4, 5};

        int sum = Arrays.stream(ar) // 스트림을 생성
                        .filter(n -> n%2 == 1) // filter 통과
                        .sum(); // sum을 통과시켜 그 결과를 반환

        System.out.println(sum);
    }
}

위 예제에서 쓰인 두 메소드는 다음과 같다.

public static IntStream stream(int[] array)
IntStream filter(IntPredicate predicate)

filter와 sum 메소드는 IntStream의 인스턴스 메소드이다.

스트림의 연산은 "지연 처리" 방식으로 동작한다.
위 예제에서는 sum이 호출될 때까지 filter의 호출 결과는 스트림에 반영되지 않는다.
최종 연산인 sum이 호출되어야만 filter의 호출 결과가 스트림에 반영된다.
이처럼 최종 연산이 생략되면 중간 연산이 의미가 없다.

스트림 생성하기

배열

배열에 저장된 데이터를 대상으로 스트림을 생성할 때 호출되는 대표 메소드는 다음과 같다.

public satic <T> Stream<T> stream(T[] array) // Arrays 클래스에 정의되어 있다
class StringStream {
    public static void main(String[] args) {
        String[] names = {"YOON", "LEE", "PARK"};
        
        // 스트림 생성
        Stream<String> stm = Arrays.stream(names);
        
        // 최종 연산 진행
        stm.forEach(s -> System.out.println(s));
    }
}

forEach는 최종 연산이며 메소드의 매개변수형은 Consumer<T> 이므로 람다식을 인자로 전달해야하며,
내부적으로 스트림 데이터를 하나씩 인자로 전달하면서 accept 메소드를 호출한다.

컬렉션 인스턴스

컬렉션 인스턴스를 대상으로 스트림을 생성할 때 호출되는 메소드는 다음과 같다.

default Stream<E> stream()
class ListStream {
    public static void main(String[] args) {
        
        List<String> list = Arrays.asList("Toy", "Robot", "Box");
        
        list.stream()
          .forEach(s -> System.out.print(s + "\t"));

        System.out.println();
    }
}

스트림의 중간 연산

filter (필터링)

스트림을 구성하는 데이터 중 일부를 조건에 따라 걸러내는 행위를 의미한다.

메소드

Stream<T> filter(Predicate<? super T> predicate) // Stream<T>에 존재

매개변수 형이 Predicate이므로 test 메소드의 구현에 해당하는 람다식을
인자로 전달해야 한다.
내부적으로 스트림 데이터를 하나씩 인자로 전달하면서 test를 호출하고,
그 결과가 true이면 해당 데이터를 스트림에 남긴다.

class FilterStream {
    public static void main(String[] args) {
        int[] ar = {1, 2, 3, 4, 5};
        Arrays.stream(ar)
            .filter(n -> n%2 == 1) // 홀수만 통과
            .forEach(n -> System.out.print(n + "\t"));
        System.out.println();

        List<String> sl = Arrays.asList("Toy", "Robot", "Box");
        sl.stream()
            .filter(s -> s.length() == 3) // 길이가 3이면 통과
            .forEach(s -> System.out.print(s + "\t"));
        System.out.println();       
    }
}

map (맵핑)

맵핑을 진행하면 스트림의 데이터 형이 달라지는 특징이 있다.

메소드

<R> Stream<R> map(Function<? super T, ? extends R> mapper)

매개변수 형이 Function이므로 apply 메소드의 구현에 해당하는 람다식을
인자로 전달해야 한다.
내부적으로 스트림 데이터를 하나씩 인자로 전달하면서 apply를 호출하고,
그 결과로 반환되는 값을 모아 새 스트림을 생성한다.

class MapToInt {
    public static void main(String[] args) {
        List<String> ls = Arrays.asList("Box", "Robot", "Simple");
        
        ls.stream()
          .map(s -> s.length())
          .forEach(n -> System.out.print(n + "\t"));
        
        System.out.println();
    }
}

filter & map

example

int sum = ls.stream()
                       .filter(p -> p.getPrice() < 500)
                       .mapToInt(t -> t.getPrice())
                       .sum();

스트림의 최종 연산

reduce

리덕션은 데이터를 축소하는 연산을 뜻한다.

메소드

T reduce(T identity, BinaryOperator<T> accumulator) // Stream<T>에 존재

reduce는 전달하는 람다식에 의해 연산의 내용이 결정된다.

BinaryOperator<T>의 추상 메소드

T apply(T t1, T t2)

reduce 호출 시 메소드 apply에 대한 람다식을 인자로 전달해야 한다.

class ReduceStream {
    public static void main(String[] args) {
        List<String> ls = Arrays.asList("Box", "Simple", "Complex", "Robot");
        
        BinaryOperator<String> lc = 
            (s1, s2) -> { 
               if(s1.length() > s2.length())
                   return s1;
               else 
                   return s2;                   
            };
        
        String str = ls.stream()
                      .reduce("", lc); // 스트림이 빈 경우 빈 문자열 반환
      
        System.out.println(str); // Complex
    }
}

reduce 메소드는 스트림이 빈 경우에 첫 번째 인자로 전달된 값을 반환한다.


• • •

우테코 진행하면서 많이 사용했던 메소드였는데,
이렇게 공부하면서 정리하니까 메소드의 정의를 확실하게 깨달을 수 있었다!

profile
🚛 블로그 이사합니다 https://newwisdom.tistory.com/

0개의 댓글