티스토리 뷰

 

프로젝트를 진행하다 겪은 문제다.

람다식을 사용할 때, 특히 stream을 해 map으로 구조 변경 시 자기 자신을 인자로 넘겨주는 경우가 있는데, 이때 i -> i로 나는 그대로 넘겼다.

하지만 리펙토링을 하면서 Function.identity() i -> i 를 사용하는것의 차이가 무엇인지 궁금했다.

@Override
    public Page<EventPageInfo> findAllEventPages(Long userId, Pageable pageable) {
        Page<Event> eventPages = eventUserRepository.findAllByUserId(userId, pageable);

        List<Long> eventIds = eventPages.stream()
                .map(Event::getId)
                .toList();

        Map<Long, EventUser> eventUsers = eventUserRepository.findAllByUserIdAndEvent_IdIn(userId, eventIds).stream()
                .collect(toMap(EventUser::getEventId, Function.identity()));

        List<EventPageInfo> eventPageInfos = eventPages.getContent().stream()
                .map(event -> EventPageInfo.from(event, eventUsers.get(event.getId())))
                .toList();

        return new PageImpl<>(eventPageInfos, eventPages.getPageable(), eventPages.getTotalElements());
    }

 

기존에는 아래와 같이 동일한 값을 넘길때 i → i 같이 그대로 값을 넘겼다.

 Map<Long, EventUser> eventUsers = eventUserRepository.findAllByUserIdAndEvent_IdIn(userId, eventIds).stream()
                .collect(toMap(EventUser::getEventId, i -> i));

하지만 리팩토링을 하면서 아래와 같이 Function.identity() 로 변경을 했다.

 Map<Long, EventUser> eventUsers = eventUserRepository.findAllByUserIdAndEvent_IdIn(userId, eventIds).stream()
                .collect(toMap(EventUser::getEventId, Function.identity()));

 

둘의 차이는 뭘까?

Function 인터페이스의 identity 메서드

Function 인터페이스는 자바에서 제공하는 input과 output이 있는 함수형 인터페이스다.

그 중 자기 자신을 반환하는 identity() 메서드는 위와 같다.

 

Function.identity()identifier -> identifier를 사용하는것은 로직상 똑같다. Function을 거치냐 안거치냐의 차이인 것이다.

 

하지만 동일하지는 않다.

Function.identity()을 사용하는 것은 항상 같은 instance를 넘기지만 identifier -> identifier 를 사용하는 것은 인스턴스를 새로 생성할 뿐 아니라 별개의 implementation class를 가진다.

 

따라서 Function.identity()를 사용하는 것은 메모리를 좀 더 아낄 수 있다.

 

Does a lambda expression create an object on the heap every time it's executed?

 

Does a lambda expression create an object on the heap every time it's executed?

When I iterate over a collection using the new syntactic sugar of Java 8, such as myStream.forEach(item -> { // do something useful }); Isn't this equivalent to the 'old syntax' snippet belo...

stackoverflow.com

위 stackoverflow 질문에서도 Consumer Function을 사용하는 것과 사용하지 않는

것의 차이가 무엇인지 다루고 있다.

위 결과를 보면 차이를 느낄 수 있다.

 

결론 :

Function.identity()는 항상 같은 인스턴스를 반환하지만 identifier -> identifier 는 인스턴스를 새로 생성할 뿐 아니라 별도의 구현 클래스가 있기 때문에 Function.identity() 를 사용하는것이 메모리 측면에서 더 효율적이다.

최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday