본문 바로가기
Language/JAVA

스트림의 중간, 최종연산

by YoonJong 2023. 2. 15.
728x90

스트림의 연산에 대해 알아보겠습니다.

프로젝트를 진행할 때, for 문과 같은 코드를 Stream 으로 리팩토링을 했는데, 자바의 정석 강의를 통해 다시 한번 정리해보고자 합니다.

 

자바8 이후 Stream 을 사용할 수 있게 되면서, 길고 복잡했던 코드를 단순하고 가독성 좋게 사용할 수 있기 때문에,

낯설더라도 프로젝트에 적용하면 빠르게 배울 수 있을 거 같습니다.

 

먼저 어떠한 종류가 있는지 확인해보겠습니다. 기본적인 메서드만 정리했으며, 많은 메서드가 있습니다.

중간 연산은 0~n 개를 사용할 수 있습니다.

중간 연산 설명
Stream<T> distinct() 종복제거
Stream<T> filter( 조건식 ) 조건에 안맞는 요소는 제외
Stream<T> limit() 스트림의 일부를 잘라내기
Stream<T> skip() 스트림의 일부를 건너뛰기
Stream<T> sortd() 스트림의 요소 정렬
Stream<T> map() 스트림의 요소를 변환

 

최종연산의 메서드를 알아보겠습니다. 최종연산은 1개만 사용가능합니다.

최종연산 설명
void forEach() 각 요소에 지정된 작업 수행
long count() 스트림의 요소의 개수 반환
Optional<T> max()
Optional<T> min()
스트림의 최댓값 반환
스트림의 최솟값 반환
Optional<T> findAny()
Optional<T> findFirst()
스트림 요소를 하나 반환 (아무거나 하나)
스트림 요소를 하나 반환 (첫번째 요소)
boolean allMatch(Predicate<T> p)
boolean anyMatch(Predicate<T> p)
boolean noneMatch(Predicate<T> p)
요소를 만족시키는지 확인 (모두 만족)
요소를 만족시키는지 확인 (하나라도 만족)
요소를 만족시키는지 확인 (모두 만족X)
Object[ ] toArray() 스트림의 모든 요소를 배열로 반환
Optional<T> reduce 스트림의 요소를 하나씩 줄여가면서 계산
R collect 스트림의 요소 수집

 


skip() 과 limit() 의 예제입니다.

3개를 건너뛰고 5개를 출력합니다.

IntStream intStream = IntStream.rangeClosed(1, 10); // 1 ~ 10
intStream.skip(3).limit(5).forEach(System.out::print);

// 결과값
45678

 

distinct() 와 filter() 의 예제입니다.

distinct() 는 중복을 제거하고 filter() 는 괄호 안에 있는 조건에 맞는 요소를 필터링합니다.

IntStream intStream = IntStream.of(1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7);
intStream.distinct().forEach(System.out::print);
// 결과값
1 2 3 4 5 6 7 

IntStream intStream = IntStream.rangeClosed(1, 10); // 1 ~ 10
intStream.filter(i -> i % 2 == 0).forEach(System.out::print);
// 결과값 
2 4 6 8 10

IntStream intStream = IntStream.rangeClosed(1, 10); // 1 ~ 10
intStream.filter(i -> i % 2 == 0).filter(i -> i % 3 == 0).forEach(System.out::print);
// 결과값
6

sorted() 의 예제입니다. 괄호안에 정렬기준을 설정할 수 있습니다.

Stream<String> strStream = Stream.of("dd", "aa", "bc", "bb");
strStream.sorted((o1, o2) -> o1.compareTo(o2)).forEach(System.out::print);
// 결과값
aabbbcdd

Stream<String> strStream = Stream.of("dd", "aa", "bc", "bb");
strStream.sorted((o1, o2) -> o2.compareTo(o1)).forEach(System.out::print);
//strStream.sorted(Comparator.reverseOrder()).forEach(System.out::print);
// 결과값
ddbcbbaa

map() 을 사용하는 예제입니다. File 타입의 객체를 String 타입으로 변환할 수 있습니다.

File[] fileArr = {new File("Ex1.java"),
        new File("Ex1.bak"),
        new File("Ex2.java"),
        new File("Ex1"),
        new File("Ex1.txt")};

Stream<File> fileStream = Stream.of(fileArr);

// map() 으로 Stream<File> 을 Stream<String> 으로 변환
Stream<String> filenameStream = fileStream.map(f -> f.getName());
filenameStream.forEach(System.out::println);

//결과값
Ex1.java
Ex1.bak
Ex2.java
Ex1
Ex1.txt

최종연산 (1번만 사용가능) 에 대해 알아보겠습니다.

 

먼저 가장 기본적인 forEach() 입니다. 루프를 들면서 출력합니다.

IntStream.range(1,10).forEach(System.out::print);
IntStream.range(1,10).parallel().forEach(System.out::print);    // 병렬 처리 -> 순서보장X
IntStream.range(1,10).parallel().forEachOrdered(System.out::print); // 병렬 처리 시 순서보장

//결과값
123456789
657948213
123456789

 

anyMatch() 입니다. 괄호안에는 조건식이 들어가며, 아래는 100 점 이하의 학생이 있는지 확인하는 예제입니다.

boolean hasFailedStu = studentStream.anyMatch( s-> s.getTotalScore() <= 100);

// 결과값
존재하면 true

 

findFirst() 와 findAny() 의 사용예제입니다. filter 조건이랑 같이 사용됩니다.

findFirst 는 앞에서부터 하나씩 조회하며 필터조건에 의해 찾으면 그 값을 반환(첫번째 요소) 합니다.

값이 없을 수도 있기 때문에 Optional 입니다.

 

findAny() 는 병렬처리 시 사용합니다. 

필터조건에 맞는 값을 반환하며, 병렬 처리 시 나누어 찾기 때문에 Any를 사용합니다.

값은 먼저 찾는 값을 반환합니다.

Optional<Student> result = studentStream.filter( s-> s.getTotalScore() <= 100).findFirst();
Optional<Student> result = paralleStream.filter( s-> s.getTotalScore() <= 100).findAny();

 

reduce() 는 요소를 하나씩 줄여가며 누적연산을 수행합니다.

Optional<T> reduce (BinaryOperator<T> accumulator) : 초기값이 없으니 null 이 반환 될 수 있습니다.

T reduce(T identity, BinaryOperator<T> accumulator) : 초기값을 설정하며, 실행되지 않으면 초기값을 반환합니다.

초기값을 설정해주고, 실행할 연산을 적어줍니다.

int count = intStream.reduce(0, (a,b) -> a+1);	//count
int sum = intStream.reduce(0, (a,b) -> a+b);	//sum
int max = intStream.reduce(Integer.MIN_VALUE, (a,b) -> a > b ? a : b); //max
int min = intStream.reduce(Integer.MAX_VALUE, (a,b) -> a < b ? a : b); //min

sum 의 코드는 풀어서 작성하면 아래와 같습니다.

int a = identity;
for(int b : stream)
	a = a + b;

 

최종연산 reduce() 의 예제를 총 예제로 알아보겠습니다.

String[] strArr = {"aaa", "bbbb", "cc", "dd", "e"};

IntStream intStream1 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream2 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream3 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream4 = Stream.of(strArr).mapToInt(String::length);

int count = intStream1.reduce(0, (a, b) -> a + 1);
int sum = intStream2.reduce(0, (a, b) -> a + b);
OptionalInt max = intStream3.reduce(Math::max);
OptionalInt min = intStream4.reduce(Math::min);


System.out.println("count = " + count);
System.out.println("sum = " + sum);
System.out.println("max = " + max.getAsInt());
System.out.println("min = " + min.getAsInt());

//결과값
count = 5
sum = 12
max = 4
min = 1

 

collect() 는 그룹별로 리듀싱할때 사용합니다.

Object collect(Collerctor collector)

List<String> names = studentStream.map(Student::getName).collect(Collectors.toList());
ArrayList<String> list = names.stream().collect(Collectors.toCollection(ArrayList::new));
Map<String,Person> map = personStream.collect(Collectors.toMap(p->p.getRegId(), p->p));

 

728x90

댓글