개발일지/Java

Java 스트림(Stream)

E-room 2022. 9. 19. 22:29
728x90
배열, 컬렉션의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자

 

스트림의 특징

    1. 선언형 프로그래밍

"어떻게" 수행하는지보다는 "무엇을" 수행하는지에 관심을 두는 프로그래밍 패러다임 -> 가독성이 높다

 

일반적인 방법

// List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);
int sum = 0;

for (int number : numbers) {
    if (number > 4 && (number % 2 == 0)) {
        sum += number;
    }
}

System.out.println("# 명령형 프로그래밍 : " + sum);

stream을 이용한 방법

// List에 있는 숫자들 중에서 4보다 큰 짝수의 합계 구하기
List<Integer> numbers = List.of(1, 3, 6, 7, 8, 11);

int sum =
        numbers.stream()
                .filter(number -> number > 4 && (number % 2 == 0))
                .mapToInt(number -> number)
                .sum();

System.out.println("# 선언형 프로그래밍: " + sum);

 

    2. 람다식으로 요소 처리 코드를 제공한다.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) throws Exception {
        List<Student> list = Arrays.asList(
                new Student("김이룸", 100),
                new Student("이자바", 95)
        );

        Stream<Student> stream = list.stream();
        stream.forEach(s -> {
            String name = s.getName();
            int score = s.getScore();
            System.out.println(name + " - " + score);
        });
    }
}

class Student {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }
}
// 출력
김이룸 - 100
이자바 - 95

 

    3. 내부 반복자를 사용하므로 병렬 처리가 쉽다

외부 반복자(external iterator)란 개발자가 코드로 직접 컬렉션의 요소를 반복해서 가져오는 코드 패턴을 말한다

-> index를 사용하는 for문, Iterator를 이용하는 while문

내부 반복자(internal iterator)는 컬렉션 내부에서 요소들을 반복시키고 개발자는 요소당 처리해야 할 코드만 제공하는 코드 패턴

Iterator는 컬렉션의 요소를 가져오는 것에서부터 처리하는 것까지 모두 개발자가 작성해야 하지만 스트림은 람다식으로 요소 처리 내용만 전달할 뿐, 반복은 컬렉션 내부에서 일어난다

 

    4. 중간 연산과 최종 연산을 할 수 있다

컬렉션의 요소에 대해 중간 연산과 최종 연산을 수행할 수 있다.

중간 연산 : 매핑, 필터링, 정렬 등

최종 연산 : 반복, 카운팅, 평균, 총합 등의 집계


파이프라인 구성(.)

파이프라인은 여러 개의 스트림이 연결되어 있는 구조이다.

최종 연산을 제외하고는 모두 중간 연산 스트림이다.

// 파이프라인을 코드로 표현하면
Stream<Member> maleFemaleStream = list.stream();
Stream<Member> maleStream = maleFemaleSTream.filter(m -> m.getGender() == Member.MALE);
IntStream ageStream = maleStream.mapToInt(Member::getAge);
OptionalDouble opd = ageStream.average();
double ageAve = opd.getAsDouble();

// 로컬 변수를 생략하고 연결하면
double ageAve = list.stream() //오리지널 스트림
                .filter(m -> m.getGender() == Member.MALE) //중간 연산 스트림
                .mapToInt(Member::getAge) //중간 연산 스트림
                .average() //최종 연산
                .getAsDouble();

 

728x90