이펙티브 코틀린 8장 효율적인 컬렉션 처리

Rm·2022년 4월 11일
0

이펙티브 코틀린

목록 보기
8/8
post-thumbnail

8장 효율적인 컬렉션 처리

컬렉션은 프로그래밍에서 굉장히 중요한 개념이다.
컬렉션 처리 최적화는 생각보다 어렵지만 굉장히 중요하다. 특시 백엔드 애플리케이션 개발, 데이터 분석 등의 영역에서는 컬렉션 처리 최적화만 잘해도 프로그램의 전체적인 성능이 향상된다.

Item49 하나 이상의 처리 단계를 가진 경우에는 시퀀스를 사용하라

많은 사람이 Iterable과 Sequence의 차이를 잊어 버린다.
Iterable과 Sequence는 완전히 다른 목적으로 설계되어서, 완전히 다른 형태로 동작한다. Sequence는 지연 처리된다.
따라서 시퀀스 처리 함수들을 사용하면, 데코레이터 패턴으로 꾸며진 새로운 시퀀스가 리턴된다.

반면, Iterable은 처리 함수를 사용할 때마다 연산이 이루어져 List가 만들어진다.

컬렉션 처리 연산은 호출할 때 연산이 이루어진다.반면, 시퀀스 처리 함수는 최종 연산이 이루어지기 전까지는 각 단계에서 연산이 일어나지 않는다.

순서의 중요성

이터러블 처리와 시퀀스 처리는 연산의 순서가 달라지면, 다른 결과가 나온다.
시퀀스 처리는 요소 하나하나에 지정한 연산을 한꺼번에 적용하며 이를 전문적으로 element-by-element order 또는 lazy order라고 부른다.

반면 이터러블은 요소 전체를 대상으로 연산을 차근차근 적용해 나간다. 이를 전문적으로 step-by-step order 또는 eager order라고 부른다.

최소 연산

컬렉션에 어떤 처리를 적용하고, 앞의 요소 10개만 필요한 상황은 굉장히 자주 접할 수 있는 상황이다.
이터러블 처리는 기본적으로 중간 연산이라는 개념이 없으므로, 원하는 처리를 컬렉션 전체에 적용한 뒤, 앞의 요소 10개를 사용해야 한다.

무한 시퀀스

시퀀스는 실제로 최종 연산이 일어나기 전까지는 컬렉션에 어떠한 처리도 하지 않습니다. 따라서 무한 시퀀스를 만들고, 필요한 부분까지만 값을 추출하는 것도 가능하다.

각각의 단계에서 컬렉션을 만들어 내지 않음

표준 컬렉션 처리 함수는 각각의 단계에서 새로운 컬렉션을 만들어 낸다. 일반적으로 대부분 List이며 각각의 단계에서 만들어진 결과를 활용하거나 저장할 수 있다는 것은 컬렉션의 장점이지만, 각각의 단계에서 결과가 만들어지면서 공간을 차지하는 비용히 든다는 것은 큰 단점이다.

시퀀스가 빠르지 않은 경우

컬렉션 전체를 기반으로 처리해야 하는 연산은 시퀀스를 사용해도 빨라지지 않습니다.

sorted는 Sequence보다 Collection이 더 빠른 희귀한 예입니다. 다른 처리는 모두 Sequence가 빠르므로, 여러 처리가 결합된 경우에는 Collection을 사용하는 것보다 Sequence를 사용하는 것이 더 빠르다.

자바 스트림의 경우

자바 8부터는 컬렉션 처리를 위해 스트림 기능이 추가되었다.

자바의 스트림과 코틀린의 시퀀스는 다음과 같은 세 가지 큰 차이점이 있다.

  • 코틀린의 시퀀스가 더 많은 처리 함수를 갖고 있다.
  • 자바 스트림은 병렬 함수를 사용해서 병렬 모드로 실행할 수 있다. 이는 멀티 코어 환경에서 굉장히 큰 성능 향상을 가져온다.
  • 코틀린의 시퀀스를 코틀린/JVM, 코틀린/JS, 코틀린/네이티브 등의 일반적인 모듈에서 모두 사용할 수 있다. 하지만 자바 스트림은 코틀린/JVM에서만 동작하며, 그것도 JVM이 8 버전 이상일 때만 동작한다.

코틀린 시퀀스 디버깅

코틀린 시퀀스와 자바 스트림은 모두 단계적으로 요소의 흐름을 추적할 수 있는 디버깅 기능이 지원된다.

결론

시퀀스는 lazy하게 처리된다. 이로 인해서 다음과 같은 장점이 발생합니다.

  • 자연스러운 처리 순서를 유지한다.
  • 최소한만 연산한다.
  • 무한 시퀀스 형태로 사용할 수 있다.
  • 각각의 단계에서 컬렉션을 만들어 내지 않는다.

결과적으로 무거운 객체나 규모가 큰 컬렉션을 여러 단계에 걸쳐서 처리할 때는 시퀀스를 사용하는 것이 좋다.
상황에 따라서 시퀀스 처리를 활용하면 큰 성능 향상이 있을 수 있다.

Item50 컬렉션 처리 단계 수를 제한하라

모든 컬렉션 처리 메서드는 비용이 많이 든다.

대부분의 컬렉션 처리 단계는 전체 컬렉션에 대한 반복과 중간 컬렉션 생성이라는 비용이 발생한다. 이 비용은 적절한 컬렉션 처리 함수들을 활용해서 줄일 수 있습니다.

Item51 성능이 중요한 부분에는 기본 자료형 배열을 사용하라

코틀린은 기본 자료형을 선언할 수 없지만, 최적화를 위해서 내부적으로는 사용할 수 있다.

일반적으로 Array보다 List와 Set을 사용하는 것이 좋다. 하지만 기본 자료형의 컬렉션을 굉장히 많이 보유해야 하는 경우에는 성능을 높이고, 메모리 사용량을 줄일 수 있도록 Array를 사용하는 것이 좋다.

Item52 mutable 컬렉션 사용을 고려하라

immutable 컬렉션보다 mutable 컬렉션이 좋은 점은 성능적인 측면에서 더 빠르다는 것이다. immutable 컬렉션에 요소를 추가하려면, 새로운 컬렉션을 만들면서 여기에 요소를 추가해야 한다.

가변 컬렉션은 일반적으로 추가 처리가 빠르다.

immutable 컬렉션은 컬렉션 변경과 관련된 처리를 더 세부적으로 조정할 수 있다. 일반적으로 지역 스코프에서는 이러한 세부적인 조정이 필요하지 않으므로, 가변 컬렉션을 사용하는 것이 좋다. 특히 utils에서는 요소 삽입이 자주 발생할 수 있기 때문이다.

느낀 점

기존에 컬렉션은 Java에서 간편하게 활용하는 정도로만 생각했었지 성능적인 측면을 고려해보진 않았던 것 같다.
하지만 이번 장에서 컬렉션을 효율적으로 활용하는 과 Java의 스트림과 코틀린의 시퀀스를 비교 설명하여 좋았던 것 같다.
하지만 아직 Java나 코틀린 컬렉션이 익숙하지 않아 확 와닿는 부분들이 부족해서 추후 다시 읽어볼 예정이다.

profile
우당탕 개발자 성장기

0개의 댓글