[JAVA] 스트림(Stream) - 2

nimoh·2023년 2월 22일
0

지난 시간에는 스트림을 생성하는 방법까지 알아보았다.
오늘은 스트림의 중간연산 중 스트림 자르기와 걸러내기에 대해 기록하려고 한다.

스트림의 중간연산

이전 포스팅에서도 얘기한 바 있지만 중간연산은 말 그대로 중간에서 연산만 해주는 역할이다. 스트림의 최종연산이 호출되기 전까지는 중간연산은 수행되지 않는다. 최종연산을 수행할 때 중간 중간에 이런 연산을 하겠다 라는 선언만 해주는 것이다.

스트림의 중간연산에는 어떤 것이 있는 지 알아보자.

스트림 자르기 - skip(), limit()

스트림을 잘라서 연산할 수 있다. skip()과 limit()이 있는데 둘의 사용법은 매우 간단하다.

skip()

skip()은 스트림의 첫 요소부터 지정한만큼 생략(skip)하고 연산을 시작할 수 있다.

	Stream<Integer> intStream = Arrays.stream(new Integer[]{1,2,3,4,5});
    intStream.skip(2).forEach(System.out::print); // 첫 2개를 생략!
    결과 : 345

limit()

limit()은 다음 스트림으로 넘겨주는 요소의 개수를 지정한 만큼 제한한다.

	IntStream randomStream = new Random().ints(1,11); // 1부터 11까지 랜덤으로 출력해주는 Random 클래스의 스트림
    randomStream.limit(5).forEach(System.out::println); // 5개로 제한
    결과 : 2 9 10 1 5

이전 장에서 난수 스트림을 만드는 방법에 대해 알아보았다. 난수를 만들 때 limit() 중간 연산을 이미 사용한 적이 있다. 난수 스트림은 무한 스트림이기때문에 개수 제한을 두지 않으면 골치아프다.

혹시 기억이 안난다거나 보지 않았다면 스트림 난수 만들기를 참조하길 바란다.

스트림 요소 걸러내기 - filter(), distinct()

중간 요소의 이름들이 매우 직관적이다.
filter()는 말 그대로 필터링하는 것이다. 어떤 조건(predicate 람다식)에 해당하는 요소만 남기고 나머지는 걸러낸다.

	Stream<T> filter(Predicate<? super T> predicate)

Predicate 람다식도 이전 포스팅에서 얘기했으므로 자세한 설명은 생략하겠다. 지금은 조건식을 통해 boolean을 반환하는 람다식이라고만 알면 된다.

   Stream<Integer> intStream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5});
   intStream.filter(i->i>3).forEach(System.out::println); 
   결과: 4 5

filter()

filter()를 자세히 보면 매개변수로 각 요소(i)를 가져와서 i>3인 경우만 남기고 나머지는 걸러낸다(필터링한다).
필요하다면 filter()를 여러 번 사용해도 상관없다.

	IntStream intStream = IntStream.rangeClosed(1, 10);
	intStream.filter(i->i % 2==0).filter(i->i > 5).forEach(System.out::println);
    결과: 6 8 10

IntStream.rangeClosed()는 특정범위의 정수를 순차적으로 스트림 요소에 저장하여 스트림을 생성하는 것을 말한다.(참조)
rangeClosed(1,10)은 1부터 10까지이다. range()라면 1부터 9까지를 의미한다.
어쨌든 중요한 것은 filter가 두 개 들어갔다는 것이다. 첫번째 filter는 연속된 정수 1~10 중에 짝수인 것만 남긴다. 그럼 홀수는 모두 걸러지고 스트림 요소에 (2, 4, 6, 8, 10)이 남아있을 것이다. 그 다음 필터에서는 5보다 큰 수만 남긴다. 그럼 스트림 요소에는 (6, 8, 10)만 남는다. 때문에 출력해보면 6 8 10이 나온다.

distinct()

distinct()는 중복제거이다.

	Stream<T> distinct()
	Stream<Integer> intStream = Arrays.stream(new Integer[]{1, 1, 2, 2, 2, 3});
    intStream.distinct().forEach(System.out::println);
    결과 : 1 2 3

스트림이 distinct()연산을 만나기 전까진 {1, 1, 2, 2, 2, 3}의 요소를 가지고 있다. distinct()를 통해 중복된 요소들을 걸러내면 결과는 1, 2, 3이 남는다.

나가며

스트림의 갈 길은 아직 멀고도 험하다. 특히 sorted() 중간연산이나 collect() 최종연산을 이해하기 위해서는 Comparator에 대한 이해가 필수적으로 필요하다. 다음 포스팅에는 Stream과 직접적인 관계는 없지만 자주 등장하는 Comparator에 대해 알아보고자 한다.

참조 : 자바의 정석 3rd Edition

profile
부족함을 인정하는 순간이 성장의 시작점이다.

0개의 댓글