3 분 소요

배열, 컬렉션의 저장 요소를 하나씩 참조해 람다식으로 처리할 수 있도록 하는 반복자

List, Set, Map 등 다양한 데이터 소스로부터 스트림을 만들 수 있음


// 명령형 방식
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;
    }
}

// 선언형 방식
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();

배열 스트림 생성

Arrays 클래스의 stream() 메서드 또는 Stream클래스의 of() 메서드를 사용할 수 있다.

Arrays.stream()

// 문자열 배열 선언 및 할당
String[] arr = new String[]{"김코딩", "이자바", "박해커"};

// 문자열 스트림 생성
Stream<String> stream = Arrays.stream(arr);

// 출력
stream.forEach(System.out::println);

Stream.of()

// 문자열 배열 선언 및 할당
String[] arr = new String[]{"김코딩", "이자바", "박해커"};

// 문자열 스트림 생성
Stream<String> stream = Stream.of(arr);

// 출력
stream.forEach(System.out::println);

배열로 스트림을 생성할 시에는 Arrays.stream()Stream.of() 둘 중 더 편한 메서드를 선택하여 사용할 수 있다.

컬렉션 스트림 생성

List, Set 등의 경우, stream() 메서드를 사용하여 스트림을 생성할 수 있다.

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
Stream<Integer> stream = list.stream();

stream.forEach(System.out::print);

중간 연산

wMp3VBLNX170s4u6qWaFw-1672900754851.png

필터링

  • distinct() 중복된 데이터가 존재하는 경우, 중복을 제거하기 위해 사용한다.
  • filter() 조건에 맞는 데이터만 정제하여 더 작은 컬렉션을 만든다.
List<String> names = Arrays.asList("가가", "나나", "다다", "가가", "잉잉");

names.stream()
        .distinct() //중복제거
        .filter(element -> element.startsWith("김")) // 김씨 성을 가진 요소만 필터링 
        .forEach(element -> System.out.println(element));

매핑

원하는 필드만 추출하거나 특정 형태로 변환할 때 사용한다.

**.map()**

List<String> names = Arrays.asList("aa", "bb", "cc");

names.stream()
        .map(element -> element.toUpperCase()) // 요소들을 하나씩 대문자로 변환
        .forEach(element->System.out.println(element));
List<Integer> list = Arrays.asList(1, 3, 6, 9);

// 각 요소에 3을 곱한 값을 반환
list.stream().map(number -> number * 3).forEach(System.out::println);

**.flatMap()**

중첩 구조를 제거하고 단일 컬렉션으로 만들어주는 역할을 한다.

// map() 사용
        Arrays.stream(namesArray)
                .map(inner -> Arrays.stream(inner))
                .forEach(System.out::println);

// 출력값
java.util.stream.ReferencePipeline$Head@3cb5cdba
java.util.stream.ReferencePipeline$Head@56cbfb61

// flatMap()
Arrays.stream(namesArray).flatMap(Arrays::stream).forEach(System.out::println);

// 출력값
aa
bb
cc

정렬

정렬할 때 사용한다.

List<String> animals = Arrays.asList("T", "L", "M", "D", "H", "C");

animals.stream().sorted().forEach(System.out::println);
// 출력값
C
D
H
L
M
T

역순으로 정렬

List<String> animals = Arrays.asList("T", "L", "M", "D", "H", "C");

animals.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
// 출력값
T
M
L
H
D
C

기타

  • skip() - 스트림의 일부 요소들을 건너뛴다.
  • limit() - 스트림의 일부를 자른다.
  • peek() - forEach() 와 마찬가지로, 요소들을 순회하며 특정 작업을 수행한다

    peek() 는 중간 연산자이기 때문에 여러번 연결하여 사용할 수 있는 반면,

    forEach()는 최종 연산자이기 때문에 한번만 사용 가능하다.

스트림 최종 연산

기본 집계

sum(), count(), average(), max(), min()

int[] intArray = {1,2,3,4,5};

// 배열의 첫 번째 요소 
int first = Arrays.stream(intArray).findFirst().getAsInt(); // 1

// 최소값
int min = Arrays.stream(intArray).min().getAsInt(); // 1

// 최대값
int max = Arrays.stream(intArray).max().getAsInt(); // 5

// 합계
long sum = Arrays.stream(intArray).sum(); // 15

// 평균
double average = Arrays.stream(intArray).average().getAsDouble(); // 3.0

// 카운팅
long count = Arrays.stream(intArray).count(); // 5

최종 연산자 뒤에 getAsInt(), getAsDouble() 메서드가 있는 이유

OptionalDouble average = Arrays.stream(intArr).average(); // OptionalDouble[3.0]
double result = average.getAsDouble(); // 3.0

매칭

allMatch(), anyMatch(), noneMAtch()

  • allMatch() - 모든 요소들이 조건을 만족하는 지 여부를 판단한다.
  • noneMatch() - 모든 요소들이 조건을 만족하지 않는 지 여부를 판단한다.
  • anyMatch() - 하나라도 조건을 만족하는 요소가 있는 지 여부를 판단한.
int[] intArray = {2,4,6};

boolean result = Arrays.stream(intArray).allMatch(element-> element % 2 == 0);
//true

result = Arrays.stream(intArray).anyMatch(element-> element % 3 == 0);
// true

 result = Arrays.stream(intArray).noneMatch(element -> element % 3 == 0);
 //false

요소 소모

스트림의 요소를 줄여나가면서 연산을 수행하고 최종적인 결과를 반환한다.

  • **reduce()**
int[] intArray = {1,2,3,4,5};

int sum1 = Arrays.stream(intArray)
        .map(element -> element * 2)
            .reduce((a , b) -> a + b)
        .getAsInt();
// 30
  1. .map(각 요소에 2를 곱해줌)
  2. .reduce((a , b) -> a + b) (a: 누적 값, b: 새로 더해질 값)
  3. 2+4 → a: 6, b: 6
  4. 6+6 → a:12, b: 8
  5. 12+8 → a:20, b: 10
  6. 20+10 → 최종 결과 30

요소 수집

public class TerminalOperationExample {

    public static void main(String[] args) {
        // Student 객체로 구성된 배열 리스트 생성 
        List<Student> totalList = Arrays.asList(
                new Student("김코딩", 100, Student.Gender.Male),
                new Student("박해커", 80, Student.Gender.Male),
                new Student("이자바", 90, Student.Gender.Female),
                new Student("나미녀", 60, Student.Gender.Female)
        );
        
        // 스트림 연산 결과를 Map으로 반환
        Map<String, Integer> maleMap = totalList.stream()
                .filter(s -> s.getGender() == Student.Gender.Male)
                .collect(Collectors.toMap(
                        student -> student.getName(), // Key
                        student -> student.getScore() // Value
                ));

        // 출력
        System.out.println(maleMap);
    }
}

class Student {
    public enum Gender {Male, Female};
    private String name;
    private int score;
    private Gender gender;

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

    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }

    public Gender getGender() {
        return gender;
    }
}

// 출력값
{김코딩=100, 박해커=80}

카테고리: ,

업데이트:

댓글남기기