자바/자바 입문 공부일지

자바 기초 공부 일지 50. 스트림Stream, 필터링과 맵핑

Tomitom 2022. 11. 7. 09:51
반응형

 

● 스트림Stream

스트림은 데이터가 흘러가는 줄기예요. 

데이터가 흘러 들어가서 결과를 출력하기까지의 과정이 담긴 줄기입니다. 

마치 파이프를 연결해놓고, 그 사이에 필터를 넣을 수 있는 것처럼

스트림 안에도 필터를 끼어서 원하는 결과만을 얻을 수도 있어요.

 

스트림을 생성하고 이를 대상으로 ‘중간 연산’과 ‘최종 연산’을 진행하면, 원하는 기준으로 데이터를 필

터링하고 필터링 된 데이터의 가공된 결과를 얻을 수 있습니다. 

중간 연산 성격의 메소드가 있고, 최종 연산 성격의 메소드가 있습니다. 

 

아래의 예시를 같이 보겠습니다. 

 

public static void main(String[] args) {
   int[] ar = {1, 2, 3, 4, 5};
   IntStream stm1 = Arrays.stream(ar);   // 배열 ar로부터 스트림 생성.  IntStream 은 Stream의 참조형. 배열에서 스트림을 뽑아내는 스테틱 메소드 사용. 
   IntStream stm2 = stm1.filter(n -> n%2 == 1);   // 중간 연산 진행. 주어진 기능을 토대로 해서 걸러냅니다. true 만 다시 흘러내려갑니다. 
   int sum = stm2.sum();   // 최종 연산 진행. 최종 연산을 생략하면 아무 결과도 얻지 못합니다.
   System.out.println(sum);
}

 

이 과정을 메소드 체인으로 표현하자면 다음과 같습니다. 

표현방식은 일종의 약속과도 같습니다. (조금 더 선호되는 방법!) 

 

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 <T> Stream<T> stream(T[] array)   // Arrays 클래스에 정의

 

 

public static void main(String[] args) {

   String[] names = {"YOON", "LEE", "PARK"}; // 배열 생성 

   Stream<String> stm = Arrays.stream(names);   // 스트림 생성

   stm.forEach(s -> System.out.println(s));   // 최종 연산 진행

}

 

이것을 메소드 체인으로 연결해서 실제로는 이렇게 코딩합니다. 

 

public static void main(String[] args) {

   String[] names = {"YOON", "LEE", "PARK"};

   Arrays.stream(names)

         .forEach(s -> System.out.println(s));

}

 

스트림은 배열을 대상으로 활용할 수 있는 다양한 메소드들이 존재합니다.

    Arrays 클래스에 정의된 메소드들은 다음과 같습니다. 

 

- public static IntStream stream(int[] array)

public static IntStream stream(int[] array, int startInclusive, int endExclusive)

public static DoubleStream stream(double[] array)

public static DoubleStream stream(double[] array, int startInclusive, int endExclusive)

public static LongStream stream(double[] array)

public static LongStream stream(double[] array, int startInclusive, int endExclusive)

 

이에 대한 예시를 코드를 통해 확인해볼게요. 

인덱스를 지정할 때에는 시작하는 인덱스는 포함하지만 끝나는 인덱스는 그 앞까지만 포함한다는 것을 참고해야 해요. 

 

public static void main(String[] args) {

   double[] ds = {1.1, 2.2, 3.3, 4.4, 5.5};  // 배열 생성

   Arrays.stream(ds)	// ds로 스트림 생성
	
         .forEach(d -> System.out.print(d + "\t"));		// 최종 연산 진행 

   System.out.println();	// 줄바꿈

   Arrays.stream(ds, 1, 4) // 인덱스 1부터 인덱스 4 이전까지의 배열로 스트림 생성

         .forEach(d -> System.out.print(d + "\t"));		// 최종 연산 진행 

   System.out.println();	// 줄바꿈

}

 

 

● 컬렉션 인스턴스 배열에 대해서 확인해볼게요. 

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

 

default Stream<E> stream()      // java.util.Collection<E>의 디폴트 메소드 (컬렉션 인터페이스에 정의가 되어 있다.) 

  

 

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();

}

 

 

● 필터링은 중간 연산입니다. 

즉 스트림을 구성하는 데이터 중 일부를 조건에 따라 걸러내는 연산이에요. 

 

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

      // Predicate<T> boolean test(T t) 불리언 결과를 반환하는 Predicate 함수라고 한다면 

 

 

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();

}

 

 

맵핑은 주어진 것을 가지고 새로운 데이터를 하나씩 만드는 연산이에요. 

 

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();  // 최종 출력 연산 

}

 

수월한 맵핑을 위한 키워드가 있습니다. 

IntStream mapToInt(ToIntFunction<? super T> mapper)   // Int 형을 반환하는 맵핑

LongStream mapToLong(ToLongFunction<? super T> mapper)   // Long 형을 반환하는 맵핑

DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper)   //Double 형을 반환하는 맵핑

 

필터링 후 맵핑에 대한 예제를 하나 보겠습니다. 

 

import java.util.List;
import java.util.ArrayList;

class ToyPriceInfo {        // 모델과 가격에 대한 선언
    private String model;
    private int price;
    
    public ToyPriceInfo(String m, int p) {
        model = m;
        price = p;
    }

    public int getPrice() {     // 가격의 자료 반환 
        return price;
    }
}

class ToyStream {
    public static void main(String[] args) {
        List<ToyPriceInfo> ls = new ArrayList<>();      // 배열 생성
        ls.add(new ToyPriceInfo("GUN_LR_45", 200));     // 배열에 요소들 추가 
        ls.add(new ToyPriceInfo("TEDDY_BEAR_S_014", 350));
        ls.add(new ToyPriceInfo("CAR_TRANSFORM_VER_7719", 550));
                  
        int sum = ls.stream()        // 스트림 생성
                       .filter(p -> p.getPrice() <  500)      // 필터생성
                       .mapToInt(t -> t.getPrice())     // 중간 맵핑
                       .sum();
        
        System.out.println("sum = " + sum);     // 최종 결과 출력 
    }
}

 

반응형