자바 - Stream 중개 연산

namkun·2022년 10월 3일
0

JAVA

목록 보기
11/20

중개 연산?

Stream API에서 생성된 초기 스트림은 중개 연산을 통해서 새로운 스트림으로 변환된다.

이러한 중개 연산은 스트림을 전달받아서 스트림을 반환하므로, 중개 연산은 연속으로 사용할 수 있다.

또한 중개 연산은 filter-map 기반의 API를 사용함으로 지연(lazy) 연산을 통해 성능을 최적화 할 수 있다.

아래는 대표적인 중개 연산에 대한 설명이다.

스트림 필터링

filter()

filter 메서드는 해당 스트림에서 조건에 맞는 요소만으로 구성된 새로운 스트림을 반환한다.

IntStream.of(1, 2, 3, 4)
	.filter(n -> n % 2 != 0)
    .forEach(System.out::println);
    
// result
1
3

distinct()

distinct 메서드는 해당 스트림에서 중복된 요소가 제거된 새로운 스트림을 반환한다.

IntStream.of(1, 2, 1, 3, 4, 1, 5)
		.distinct()
		.forEach(System.out::println);
        
// result
1
2
3
4
5

스트림 변환

map()

map 메서드는 해당 스트림의 요소들을 주어진 함수에 인수로 전달해서 그 반환 값들로 이루어진 새로운 스트림을 반환한다.

Stream.of("hi", "ho", "hu")
	.map(s -> s.length(System.out::println);
    
 // result
 2
 2
 2

flatMap()

스트림의 요소가 배열일 경우, flatMap 메서드를 사용해서 각 배열의 반환값을 하나의 스트림으로 합쳐서 리턴할 수 있다.

우선 map 을 사용하면 어떻게 나오는지 알아보자.

String [] animal = ["hi", "ho"] 

Arrays.stream(animal)
				.map(arr -> arr.split("")) // Stream<String[]>
				.collect(Collectors.toList()) // List<String[]>
				.forEach(arr -> System.out.println(Arrays.toString(arr)));
                
// result
[h, i]
[h, o]

배열이 따로따로 생성되어서 split 된 결과가 나오는 것을 알 수 있다.

그럼 flatMap 을 사용해보자.

String [] animal = {"hi","ho"};

Arrays.stream(animal)
		.map(arr -> arr.split("")) // Stream<String[]>
		.flatMap(Arrays::stream) //  Stream<String>
		.collect(Collectors.toList()) // List<String>
		.forEach(System.out::println);

// result
h
i
h
o

mapToInt(), mapToLong(), mapToDouble()

스트림을 각각 IntStream, LongStream, DoubleStream으로 변환해주는 메서드이다.

List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(2);

// list to arr(Integer)
int[] arr = intList.stream() // Stream<Integer>
					.mapToInt(Integer::intValue) // IntStream
                    .toArray();

위에서 mapToInt를 통해서 Integer -> int로 바꿔주는 중개 연산을 수행하는 것을 확인할 수 있다.

mapToObj()

위와 반대로 기본형 특화 스트림을 일반 스트림으로 변환해주는 메서드이다.

IntStream.of(1, 2, 3, 5) // IntStream
         .mapToObj(i -> i + "번") // Stream<String>
         .forEach(System.out::println);

// result
1235

boxed()

IntStream, LongStream, DoubleStream과 같은 기본 타입에 특화된 스트림을 일반 스트림으로 변환할 수 있다.

// Int 타입의 스트림을 일반 스트림으로 변환
Stream<Integer> boxedStream = IntStream.range(0, 3).boxed();

스트림 제한

limit()

limit 메서드는 해당 스트림의 첫 번째 요소부터 전달되는 개수만큼의 요소만으로 이루어진 새로운 스트림을 리턴한다.

IntStream.range(0, 10)
	.limit(5)
    .forEach(System.out::println);
 
 // result
 0
 1
 2
 3
 4

skip()

해당 스트림의 첫 번째 요소부터 전달된 개수 만큼의 요소를 제외한 스트림을 리턴한다.

IntStream.range(0, 10)
	.skip(3)
    .forEach(System.out::println);
 
 // result
 3
 4
 5
 6
 7
 8
 9

스트림 정렬

sorted()

sorted는 스트림을 주어진 비교자(Comparator)를 통해서 정렬한다.

비교자가 없다면 기본적으로 사전순으로 정렬된다.

Stream.of("a", "cd", "ezxc", "der")
		.sorted()
		.forEach(System.out::println);

System.out.println();

Stream.of("a", "cd", "ezxc", "der")
		.sorted(Comparator.reverseOrder())
		.forEach(System.out::println);
                
// result
a
cd
der
ezxc

ezxc
der
cd
a

스트림 결과 조회

peek()

peek은 연산과 연산 사이에 정상적으로 연산이 되었는지 확인할 때 사용한다.

forEach()와 달리 스트림의 요소를 소모하지 않으므로 연산 사이에 여러 번 끼워넣어도 문제가 되지 않는다.

고로 디버깅할 때 자주 사용된다.

IntStream.of(1,2,3,4,5)
		.filter(a -> a%2 == 0)
		.peek(System.out::println)
		.forEach(s -> System.out.println("peek test!"));
        
// result
2
peek test!
4
peek test!

기억해야할 점은, 중개 연산 메소드는 최종 연산 메소드가 실행되지 않으면 동작하지 않는다는 점이다.

최종 연산 메서드가 없으면 최종 연산 메서드가 실행되기 전까지 지연(lazy) 된다.

profile
개발하는 중국학과 사람

0개의 댓글