[Java] 스트림

hyuk·2022년 3월 6일

Java

목록 보기
4/4

스트림(Stream)?

자료가 모여 있는 배열이나 컬렉션 또는 특정 범위 안에 있는 일련의 숫자를 처리하는 기능이 미리 구현되어 있다면 프로그램의 코드가 더 간결해지고 일관성이 있게 다룰 수 있을 것이다. 예를들면 배열의 요소들을 특정 조건을 기준으로 필터링하고 모든 필터링된 요소들을 출력하는 기능처럼 말이다. 그리고 이렇게 여러 자료의 처리에 대한 기능을 구현해 놓은 클래스가 스트림이다. 즉, 스트림을 사용하면 배열, 컬렉션 등의 자료를 일관성 있게 처리할 수 있다.


위에서 정리한 내용을 예시를 통해 이해해보자.

int[] arr = {1, 2, 3, 4, 5};
for(int i = 0; i < arr.length; ++i) {
	if(arr[i] >= 3) {
		System.out.println(arr[i]);
	}
}

위 코드는 정수 배열에서 3보다 크거나 같은 값을 필터링하고, 출력하는 예시이다. 같은 예시를 스트림을 통해 구현해보자.


int[] arr = {1, 2, 3, 4, 5};
Arrays.stream(arr)
				.filter(n -> n >= 3)
				.forEach(n -> System.out.println(n));

스트림을 사용한 코드와, 스트림을 사용하지 않은 코드를 비교해보자. 스트림을 사용한 코드는 직접 for-loop를 만들지 않아도 되고, 더 가독성이 좋다. 그리고 변경에도 유연하다.


스트림 사용법

스트림을 사용하고 싶으면 일단 우리가 스트림을 사용하고 싶은 데이터 소스(배열 또는 컬렉션 또는 연속적인 요소들)를 이용해 스트림을 생성해야 한다. 여러 데이터 소스 중 가장 자주 사용되는 배열, 컬렉션을 이용해 스트림을 생성하는 방법에 대해 정리해보자.


배열을 이용해 스트림 생성하기.

Integer[] arr = {1, 2, 3, 4, 5};
Stream<Integer> stream = Arrays.stream(arr);

Arrays 클래스의 stream() 메소드를 이용해 우리가 원하는 배열의 스트림을 생성할 수 있다.


컬렉션을 이용해 스트림 생성하기.

List<Integer> list = new ArrayList<>();
Stream<Integer> stream = list.stream();

자바의 Collection 인터페이스에는 stream() 메서드가 정의되어 있다. 따라서 컬렉션 구현 클래스들은 stream() 메서드를 이용해 컬렉션에 해당하는 스트림을 만들 수 있다.


더 정확하게 말하면 스트림을 생성하는게 아니라, 스트림을 상속받은 객체를 받아오는 것이다. 왜냐하면 스트림은 클래스가 아니라 인터페이스기 때문이다.


배열 또는 컬렉션을 이용해 스트림을 생성했다면 이제, 스트림의 메서드를 이용해 우리가 원하는 연산을 수행하면된다. 스트림 연산에는 크게 중간 연산과, 최종 연산이 있다.

중간 연산은 자료를 거르거나 변경하여 또 다른 자료를 내부적으로 생성한다. 최종 연산은 생성된 내부 자료를 소모해 가면서 연산을 수행한다. 최종연산에서는 내부 자료를 소모해 가면서 연산을 수행하기 때문에 최종연산은 마지막에 한번만 호출한다. 그리고 최종연산이 수행된 스트림은 재사용 할 수 없다.

스트림은 다양한 중간 연산 메서드, 최종 연산 메서드를 제공해준다. 따라서 모든 것을 여기에 정리하기는 힘들고 대표적인 filter, forEach 연산을 통해 어떻게 사용하는지 예시로 확인하자. 더 다양한 메서드와 사용법은 자바 공식 문서를 참고 하자.


예시

String[] arr = {"hello", "hi", "stream"};
Arrays.stream(arr)
				.filter(s -> s.length() >= 3)
				.forEach(s -> System.out.println(s));

//output
hello
stream

위 예시는 다음과 같다.

  1. arr 배열을 이용해 스트림을 만든다.
  2. 중간 연산자 filter를 사용해 요소의 길이가 3이상인 요소만 가져온다.
  3. 최종 연산자 forEach를 이용해 생성된 내부 자료를 순차적으로 출력한다.

예시에서 보듯이 스트림의 대부분의 메서드들은 함수형 인터페이스를 매개변수로 받기 때문에, 위와 같이 람다식으로 매개변수를 넘겨주면 된다.


스트림의 특징

스트림의 특징에 대해 알아보자.

  • 자료의 대상과 상관없이 동일한 연산을 수행한다.

    스트림을 사용하면 컬렉션의 여러 자료 구조에 대해 다양한 작업을 일관성 있게 처리할 수 있는 메서드를 제공한다.

  • 한 번 생성하고 사용한 스트림은 재사용할 수 없다.

    최종 연산은 내부 요소들을 소모한다고 표현했다. 즉 최종연산이 수행되면 스트림 내부 요소들은 모두 소모 되기 때문에 스트림을 재사용 할 수 없다.

  • 스트림 연산은 기존 자료를 변경하지 않는다.

    스트림 연산을 위해 사용하는 메모리 공간이 별도로 존재하기 때문에 스트림의 여러 메서드를 호출하더라도 스트림을 생성할 때 사용한 기존 자료에는 영향을 주지 않는다.

  • 스트림 연산은 중간 연산과 최종 연산이 있다.

    스트림은 중간 연산과 최종 연산이 있다. 그리고 중간 연산은 여러번 적용 가능하고 최종 연산은 마지막에 한번만 적용 가능하다. 그리고 중간 연산이 여러번 호출 되었어도, 최종 연산이 호출되어야 모든 중간 연산이 적용된다. 그리고 이런 개념을 지연 연산이라고 한다.


정리

스트림을 사용하면 배열, 컬렉션등 여러 자료들에 대해서 개발자가 하고 싶은 작업을 일관성 있게 적용할 수 있다. 또 가독성 좋은 코드를 만들 수 있다.


  • 참고

    여기서는 스트림이 무엇인지? 그리고 어떻게 사용하는지를 중점으로 정리했다. 좀더 깊은 내용은 추후에 공부하고 정리해 보겠다.


reference

Do it 자바 프로그래밍 입문

profile
안녕하세요:)

0개의 댓글