개린이 탈출기

[Java] stream 의 peek 과 map의 차이 본문

에러 해결 목록

[Java] stream 의 peek 과 map의 차이

yooverd 2024. 9. 13. 12:07
728x90
반응형
SMALL

그동안 자바에서 코드를 짤 때, 컬렉션을 순회하면서 어떠한 작업을 하고 싶을 땐, for문을 돌리거나 스트림의 map/filter 만을 이용했다.
그러다가 누군가가 peek 이라는 메서드를 사용한 것을 보았는데, 내가 평소에 map으로 처리했던 작업을 peek으로 처리하는 것 같아 보여 peek 에 대해 알아보았다.

우선 peek 영단어의 뜻은 '(재빨리) 훔쳐보다' 라는 뜻이다.

 

자바에서 peek은 다음과 같이 구현되어있다

    @Override
    public final Stream<P_OUT> peek(Consumer<? super P_OUT> action) {
        Objects.requireNonNull(action);
        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
                                     0) {
            @Override
            Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
                    @Override
                    public void accept(P_OUT u) {
                        action.accept(u);
                        downstream.accept(u);
                    }
                };
            }
        };
    }

 

map 은 다음과 같이 구현되어 있다.

    @Override
    @SuppressWarnings("unchecked")
    public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
        Objects.requireNonNull(mapper);
        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
            @Override
            Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
                return new Sink.ChainedReference<P_OUT, R>(sink) {
                    @Override
                    public void accept(P_OUT u) {
                        downstream.accept(mapper.apply(u));
                    }
                };
            }
        };
    }

 

코드를 읽어보았을 때, 가장 눈에 띄는 차이점은 두 메서드가 받는 파라미터와 반환타입이 다르다는 점이었다.

 

1. 우선 파라미터 타입을 비교해보면, Consumer 타입은 void형 인터페이스이고 Function  은 파라미터를 반환값이 있는 인터페이스이다.

 

2. 반환타입을 살펴보았을 때,  peek의 반환타입은  Stream<P_OUT>으로 현재 스트림의 데이터 타입이 그대로 유지됨을 알 수 있다.
반면에 map의 반환타입은 Stream<R> 이므로 현재 스트림의 데이터 타입이 변할 수도 있음을 알 수 있다.

 

3. 가장 내부의 accept 함수를 보면 peek 은 P_OUT 을 그대로 받아 넘기므로 결과적으로 스트림에 변화가 없고

반면에 map 은 mapper.apply(u) 를 통해  새로운 데이터타입을 전달받아 변환하므로 스트림에 변화가 생긴다.

 

...

 

그렇지만 map을 사용한다고 해서 항상 스트림 내부에서 사용하는 객체가 생성되는 것은 아니다. map 을 사용했다 하더라도 스트림 내에서 기존 객체를 그대로 반환하거나 필드만 수정하는 경우, 같은 객체가 그대로 전달되는 경우도 있다.

 

그래서 나름의 결론을 짓자면,

데이터 타입이 변환되어야 할 때는 map을 사용하고, 타입 변화가 필요 없는 경우에는 peek을 사용하면 될 것 같다!다만, map을 사용해도 타입 변화가 없는 경우에는 둘의 차이가 크지 않을 것 같다.
map 이 조금 더 광범위하게 사용되는 느낌인걸까? 

 

 

 

 

728x90
반응형
LIST