Java

[Java] Java 8의 특징(3) - Stream

재담 2022. 2. 23. 23:45

Stream(스트림)

스트림은 컬렉션에 관한 다양한 처리를 도와주는 API이다. 우선 다음 코드를 보자.

animals.sort(Comparator.comparing(Animal::getAge));
for (Animal animal : animals) {
    if (animal.getAge() >= 10) {
        System.out.println(animal.getName());
    }
}

위 코드는 동물들을 나이순으로 정렬한 뒤 10살 이상인 동물들의 이름을 출력하고 있다. 이 간단한 코드를 스트림을 이용해서 다음과 같이 바꿀 수 있다.

animals.stream()
        .sorted(Comparator.comparing(Animal::getAge))
        .filter(animal -> animal.getAge() >= 10)
        .map(Animal::getName)
        .forEach(System.out::println);

스트림을 이용하면 for 문이나 if 문을 줄이거나 안 쓸 수 있다. 또한 스트림은 데이터를 담고 있는 저장소가 아니기 때문에 스트림이 처리하는 데이터의 원본을 변경하지 않고 오직 한 번만 처리한다.

 

스트림 파이프라인

스트림은 0개 또는 다수의 중개 오퍼레이션한 개의 종료 오퍼레이션으로 이루어진다. 스트림의 데이터 소스는 오직 종료 오퍼레이션을 실행할 때에만 처리된다. 예를 들어 중개 오퍼레이션에서 콘솔 출력하는 코드를 아무리 많이 작성해도 종료 오퍼레이션이 없으면 아무 의미가 없다. 이를 Lazy 하다고 한다.

 

중개 오퍼레이션

중개 오퍼레이션은 스트림을 리턴하는 오퍼레이션이다. StatelessStateful 오퍼레이션으로 구분할 수도 있다. 대부분 Stateless지만 distinct나 sorted처럼 이전 데이터 소스를 참조해야 하는 오퍼레이션은 Stateful 오퍼레이션이다.

 

종료 오퍼레이션

종료 오퍼레이션은 스트림을 리턴하지 않는 오퍼레이션이다. 마지막에 한 개만 올 수 있다.

 

 

Stream API

중개 오퍼레이션과 종료 오퍼레이션 중에서 많이 쓰이는 API를 살펴보자.

 

중개 오퍼레이션의 API에는 다음과 같은 것들이 있다.

  • filter(Predicate) : 특정 조건으로 걸러낼 때 쓰인다.
  • map : 특정 필드만 추출할 때 쓰인다.
  • flatMap : 모든 원소를 단일 원소 스트림으로 반환할 때 쓰인다.
  • generate(Supplier) : 무제한으로 스트림을 생성할 때 쓰인다.
  • iterate(T seed, UnaryOperator) : 초기값과 함수(증감 규칙)로 무제한 스트림을 생성할 때 쓰인다.
  • limit : 개수를 제한할 때 쓰인다. generate나 iterate와 같이 쓰일 때가 많다.
  • skip : 스트림에서 몇 개를 제외할 때 쓰인다.

 

종료 오퍼레이션의 API에는 다음과 같은 것들이 있다.

  • anyMatch, allMatch, nonMatch : 스트림에 있는 데이터가 특정 조건을 만족하는지 확인할 때 쓰인다.
  • count : 스트림의 개수를 셀 때 쓰인다.
  • reduce(identity, BinaryOperator) : 엘리먼트를 비교하고 컬렉션에서 하나의 값으로 연산할 때 쓰인다.
  • collect : 스트림을 컬렉션으로 리턴할 때 쓰인다.
  • forEach : 스트림의 각 원소를 반복할 때 쓰인다.
  • min(Comparator), max(Comparator) : 각각 최솟값, 최댓값을 찾을 때 쓰인다.

Reference