프로그래밍백엔드 개발자

Kotlin에서 반복자 및 시퀀스(Sequence) 작업의 특징은 무엇인가요? 대규모 컬렉션을 효율적으로 처리하기 위해 그 사용이 중요한 이유와 시퀀스의 지연 개념은 어떻게 구성되어 있는지 설명해주세요. 코드 예제를 제시하고, 시퀀스를 일반 컬렉션보다 선호해야 하는 시나리오를 설명해주세요.

Hintsage AI 어시스턴트로 면접 통과

답변

Kotlin의 Sequence는 지연 시퀀스로, 큰 데이터 집합이나 잠재적으로 무한한 데이터 집합을 효율적으로 작업할 수 있게 해줍니다. Sequence에 대한 연산(map, filter 등)은 즉시 수행되지 않고, 대신 작업의 체인이 구축되고 결과는 필요할 때(터미널 연산 예: toList)만 계산됩니다.

중요한 이유:

  • 메모리 내에서의 중간 컬렉션 수를 최소화합니다.
  • 큰 데이터 소스나 자원 소모가 큰 데이터 소스를 사용할 때 자원 소비가 크게 줄어듭니다.
  • 데이터 흐름을 표현적으로 선언적으로 처리할 수 있게 해줍니다.

코드 예제:

val numbers = generateSequence(1) { it + 1 } .filter { it % 2 == 0 } .map { it * it } .take(5) .toList() println(numbers) // [4, 16, 36, 64, 100]

이 예에서는 시퀀스의 첫 5개 요소만 실제로 계산되며, 잠재적으로 무한한 시퀀스입니다.

시퀀스를 사용할 때:

  • 많은 중간 작업이 포함된 큰 컬렉션을 변환할 때(map/filter/체인 변환).
  • 데이터 소스가 스트림이나 무제한 집합(파일, 네트워크, 생성기)일 때.

함정 질문

일반 Kotlin 컬렉션에서 mapfilter와 같은 연산자가 지연된다고 보장할 수 있습니까? 왜 그렇습니까?

답변: 아니오, Kotlin의 표준 컬렉션 연산(List.map, List.filter 등)은 엄격히 즉시 수행됩니다. 각 연산은 중간 컬렉션을 생성하며 모든 요소를 즉시 처리합니다. 지연성은 Sequence를 사용할 때만 지원됩니다.

예제:

val data = listOf(1,2,3,4) val mapped = data.map { println("Mapping $it"); it * 2 } // 모든 값을 즉시 인쇄합니다.

주제에 대한 세부사항을 모름으로 인해 발생한 실제 오류 사례들


이야기

대규모 CSV 파일(쓰기 시 최대 기가바이트)을 처리하는 프로젝트에서, 컬렉션은 처음에 List에 완전히 로드되고, 이후 chain map/filter가 적용되었습니다. 애플리케이션은 OutOfMemory 오류가 발생하였고, 문제는 List를 Sequence로 교체함으로써 해결되었습니다. Sequence의 map/filter는 거대한 중간 리스트를 생성하지 않았습니다.


이야기

여러 DB에서 보고서를 집계하는 백엔드 서비스는 처음에 검색 결과를 List에 축적한 후 필터링했습니다: 요청이 느려지고 GC 지연이 관찰되었습니다. 생성기 + Sequence로의 교체는 데이터 집계를 즉시 가능하게 하여 지연 시간을 줄였습니다.


이야기

Java에서 마이그레이션된 프로젝트는 큰 데이터 스트림을 처리할 때 map, filter와 같은 Kotlin의 표준 확장을 사용했으며, Java 8의 스트림처럼 코드가 지연된다고 생각했습니다. 이 오류는 메모리 누수와 프로덕션에서의 갑작스러운 다운타임을 초래했습니다.