공부/JAVA

[Java] 스트림 - 스트림의 최종 연산

raptorhs 2024. 7. 8. 15:53

forEach()메서드는 대표적인 최종 연산자입니다.

스트림에는 forEach() 메서드 외에도 다양한 최종 연산자들이 존재합니다.

기본 집계(sum() , count() , average(), max() , min())

숫자와 관련된 기본적인 집계의 경우에는 대부분 최종 연산자라고 생각해도 됩니다.

 

package Stream;

import java.util.Arrays;
import java.util.OptionalDouble;

public class TerminalOperationExample {
    public static void main(String[] args) {
        //int형 배열 생성
        int[] intArray = {1, 2, 3, 4, 5};

        //카운팅
        long count = Arrays.stream(intArray).count();
        System.out.println("intArr의 전체 요소 개수 " + count);

        //합계
        long sum = Arrays.stream(intArray).sum();
        System.out.println("intArr의 전체 요소 합 " + sum);

//        double averatge = Arrays.stream(intArray).average().getAsDouble();
        OptionalDouble average = Arrays.stream(intArray).average();
        System.out.println(average);
        //기본형으로 변환
        double result = average.getAsDouble();
        System.out.println("전체 요소의 평균값 " + result);

        //최대값
        int max = Arrays.stream(intArray).max().getAsInt();
        System.out.println("최대값 " + max);

        //최소값
        int min = Arrays.stream(intArray).min().getAsInt();
        System.out.println("최소값 " + min);

        //배열의 첫번째 요소
        int first = Arrays.stream(intArray).findFirst().getAsInt();
        System.out.println( "배열의 첫 번째 요소 " + first);
    }
}

 

average() 최종연산자가 반환하는 값의 타입이 OptionalDouble, 즉 래퍼 클래스 객체로 되어있기 때문에 우리가 원하는 기본형으로 변환하는 과정이 한 번 더 필요하다는 사실이 중요합니다. 이름에서 알 수 있듯이, getAsDouble()과 getAsInt()는 객체로 반환되는 값을 다시 기본형으로 변환하기 위해 사용되는 메서드로 스트림 파이프라인과는 관계가 없다는 사실을 기억하도록 합시다.

 

매칭(allMatch(), anyMatch(), noneMatch() )

 

match()메서드는 3가지 종류가 있습니다.

allMatch() - 모든 요소가 조건을 만족하는지 여부 판단

noneMatch() - 모든 요소가 조건을 만족하지 않는지 여부 판단

anyMatch() - 하나라도 조건을 만족하는 요소가 있는지 여부 판단

 

import java.util.Arrays;

public class TerminalOperationExample {
    public static void main(String[] args) throws Exception {
        // int형 배열 생성
        int[] intArray = {2,4,6};

        // allMatch()
        boolean result = Arrays.stream(intArray).allMatch(element-> element % 2 == 0);
        System.out.println("요소 모두 2의 배수인가요? " + result);

        // anyMatch()
        result = Arrays.stream(intArray).anyMatch(element-> element % 3 == 0);
        System.out.println("요소 중 하나라도 3의 배수가 있나요? " + result);

        // noneMatch()
        result = Arrays.stream(intArray).noneMatch(element -> element % 3 == 0);
        System.out.println("요소 중 3의 배수가 하나도 없나요? " + result);
    }

}

// 출력값
요소 모두 2의 배수인가요? true
요소 중 하나라도 3의 배수가 있나요? true
요소 중 3의 배수가 하나도 없나요? false

 

요소 소모(reduce())

reduce()최종 연산자는 스트림의 요소를 줄여나가면서 연산을 수행하고 최종적인 결과를 반환합니다.

 

package Stream;

import java.util.Arrays;
import java.util.OptionalDouble;

public class TerminalOperationExample {
    public static void main(String[] args) {
        //int형 배열 생성
        int[] intArray = {1,2,3,4,5};

        //sum()
        long sum = Arrays.stream(intArray).sum();
        System.out.println("intArray 전체 요소 합: " + sum);

        //초기값이 없는 reduce()
        int sum1 = Arrays.stream(intArray)
                .map(element -> element * 2)
                .reduce((a,b) -> a+ b)
                .getAsInt();
        System.out.println("초기값이 없는 reduce(): " + sum1);

        //초기값이 있는 reduce()
        int sum2 = Arrays.stream(intArray)
                .map(element -> element * 2)
                .reduce(5, (a,b)-> a+b);
        System.out.println("초기값이 있는 reduce(): " + sum2);
    }
}
//출력값
intArray 전체 요소 합: 15
초기값이 없는 reduce(): 30
초기값이 있는 reduce(): 35

 

 

요소 수집(collect())

collect()메서드는 Collector인터페이스 타입의 인자를 받아서 처리할 수 있습니다.

좀 더 구체적으로, 스트림의 요소들을 List, Set, Map 등 다른 타입의 결과로 수집하고 싶은 경우에 collect() 메서드를 유용하게 사용할 수 있습니다.

 

package Stream;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.OptionalDouble;
import java.util.stream.Collectors;

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;
    }
}