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

  • 시퀀스 처리 함수들을 사용하면, 데코레이터 패턴으로 꾸며진 새로운 시퀀스가 리턴된다.
  • 컬렉션 처리 연산은 호출할 때 연산이 이루어지는 반면, 시퀀스 처리 함수는 최종 연산이 이루어지기 전까지는 각 단계에서 연산이 일어나지 않는다.
  • 시퀀스의 지연 처리 장점
    • 자연스러운 처리 순서를 유지한다.
    • 최소한만 연산한다.
    • 무한 시퀀스 형태로 사용할 수 있다.
    • 각각의 단계에서 컬렉션을 만들어 내지 않는다.

순서의 중요성

  • 시퀀스 처리는 요소 하나하나에 지정한 연산을 한꺼번에 적용한다.
    • element-by-element order 또는 lazy order라고 부른다.
  • 이터러블은 요소 전체를 대상으로 연산을 차근차근 적용해 나간다.
    • step-by-step order 또는 eager order라고 부른다.
  • 컬렉션 처리 함수를 사용하지 않고, 고전적인 반복문과 조건문을 활용해서 구현한다면, 시퀀스 처리인 element-by-element order와 같다.
    • 따라서 시퀀스 처리에서 사용되는 element-by-element order가 훨씬 자연스러운 처리다.

최소 연산

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

무한 시퀀스

  • 무한 시퀀스를 만들고, 필요한 부분까지만 값을 추출하는 것도 가능하다.
  • generateSequence를 사용하는 방법
    • generateSequence는 ‘첫 번째 요소’와 ‘그 다음 요소를 계산하는 방법’을 지정해야 한다.
  • sequence를 사용하는 방법
    • sequence는 중단 함수로 요소들을 지정한다.
    • 시퀀스 빌더는 중단 함수 내부에서 yield로 값을 하나씩 만들어 낸다.
  • 무한 시퀀스를 실제로 사용할 떄는 값을 몇 개 사용할지 지정해야 한다.
    • take, first, find, any, all, none, indexOf

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

  • 처리 단계가 많아지고 큰 컬렉션이면, 컬렉션 처리보다는 시퀀스 처리를 사용하는 것이 좋다.
    • 컬렉션 처리는 각 단계에서 결과를 만들어서 메모리를 많이 사용한다.
    • 코드 실행 성능도 향상된다.

시퀀스가 빠르지 않은 경우

  • 시퀀스가 컬렉션 처리보다 느려지는 유일한 예는 sorted가 있다.
  • sortedSequenceList로 변환한 뒤에, 자바 stdlib의 sort를 사용해 처리한다.

자바 스트림의 경우

  • 자바의 스트림과 코틀린의 차이점
    • 코틀린의 시퀀스가 더 많은 처리 함수를 갖고 있다. 그리고 사용하기 더 쉽다. (collect(Collectors.toList() vs toList())
    • 자바 스트림은 병렬 함수를 사용해서 병렬 모드로 실행할 수 있다.
    • 코틀린의 시퀀스는 코틀린/JVM, 코틀린/JS, 코틀린/네이티브 등의 일반적인 모듈에서 모두 사용할 수 있다. 하지만 자바 스트림은 코틀린/JVM에서만 동작하며, JVM이 8 버전 이상일 때만 동작한다.
  • 병렬 모드로 이득을 얻을 수 있는 곳에서만 자바 스트림을 사용하고, 이외의 일반적인 경우에는 코틀린 시퀀스를 사용하는 것이 좋다.

코틀린 시퀀스 디버깅

  • 자바 스트림 디버깅 플러그인: Java Stream Debugger
  • 코틀린 시퀀스 디버깅 플러그인: Kotlin Sequence Debugger

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

  • 표준 컬렉션 처리는 내부적으로 요소들을 활용해 반복을 들며, 내부적으로 계산을 위해 추가적인 컬렉션을 만들어 사용한다.
    • 시퀀스 처리도시퀀스 전테를 랩하는 객체가 만들어지며, 조작을 위해서 또 다른 추가적인 객체를 만들어낸다.
  • 두 단계 이상의 컬렉션 처리 함수를 한번에 끝내는 방법들

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

  • 기본 자료형의 특징
    • 가볍다. 일반적인 객체와 다르게 추가적으로 포함되는 것들이 없기 떄문이다.
    • 빠르다. 값에 접근할 때 추가 비용이 들어가지 않는다.
  • ListSet 에서 사용되는 제네릭 타입에는 기본 자료형을 사용할 수 없으므로, 랩핑된 타입을 사용해야 한다.
    • 성능이 중요한 코드라면 IntArrayLongArray 등의 기본 자료형을 활용하는 배열을 사용하는 것이 좋다.

mutable 컬렉션 사용을 고려하라

  • immutable 컬렉션보다 mutable 컬렉션이 좋은 점은 성능적인 측면에서 더 빠르다는 것이다.
    • immutable 컬렉션에 요소를 추가하려면, 새로운 컬렉션을 만들어서 여기에 요소를 추가해야 하는데, 컬렉션을 복제하는 비용은 굉장히 많이 든다.
  • 일반적인 지역 변수는 도익화와 캡슐화 문제가 발생하지 않으니 mutable 컬렉션을 사용하는 것이 더 합리적이다.