실무 프로젝트로 배우는 Kotlin & Spring/코틀린 고급

컬렉션

webmaster 2022. 10. 8. 16:43
728x90

컬렉션 타입

  • 코틀린 표준 라이브러리는 기본 컬렉션 타입인 List, Set, Map을 제공한다.
  • 컬렉션은 두가지 종류로 나뉜다.
    • 불변 컬렉션(Immutable) : 읽기 전용 컬렉션
    • 가변 컬렉션(mutable) : 삽입, 수정, 삭제와 같은 쓰기 작업이 가능한 컬렉션

컬렉션 다이어그램

컬랙션 생성 방법

fun main() {
    // immutable
    val currencyList = listOf("달러", "유로", "원") //한번 생성하면, 쓰기/수정/삭제 할 수 없다

    //mutable
    /*
    val mutableCurrencyList = mutableListOf<String>()
    mutableCurrencyList.add("달러")
    mutableCurrencyList.add("유로")
    mutableCurrencyList.add("원")
     */
    val mutableCurrencyList = mutableListOf<String>().apply {
        //내부에 참조를 가지고 있어 좀 더 가독성있게 코드를 작성할 수 있다
        add("달러")
        add("유로")
        add("원")
    }

    //immutable set
    val numberSet = setOf(1, 2, 3, 4)

    //mutable Set
    val mutableNumberSet = mutableSetOf<Int>().apply {
        add(1)
        add(2)
        add(3)
        add(4)
    }

    //immutable map
    val numberMap = mapOf("one" to 1, "two" to 2) //중위 표현식

    //mutableMap
    val mutableNumberMap = mutableMapOf<String, Int>()
    mutableNumberMap["one"] = 1
    mutableNumberMap["two"] = 2
    mutableNumberMap["three"] = 3

    // 컬렉션 빌더
    // 컬렉션 빌더는 내부에선 mutable 반환은 immutable
    val numberList: List<Int> = buildList {
        //buildList 내부에서 add를 사용해 값을 넣고 있다(mutableList를 사용해 값을 넣었다는 의미) -> 반환 되는 리스트는 immutable 한 리스트로, 위에서 생성한 것과 차이가 있다.
        add(1)
        add(2)
        add(3)
    }

    //linkedList
    val linkedList = LinkedList<Int>().apply { //각 구현 리스트의 생성자를 통해 리스트를 생성할 수도 있다.
        addFirst(3)
        add(2)
        addLast(1)
    }

    //arrayList
    val arrayList = ArrayList<Int>().apply {
        add(1)
        add(2)
        add(3)
    }
    
}
  • 표준 라이브러리 함수를 사용
  immutable mutable
리스트 listOf() mutableListOf<>()
setOf() mutableSetOf<>()
mapOf(key to value) mutableMapOf<>()
  • apply를 사용해 가독성 좋게 생성할 수 있다.
  • 컬렉션 빌더를 사용해 컬렉션을 생성할 수 있다.
    • buildList, buildSet, buildMap 3종류 제공
    • build 내부에선 Mutable, 반환할 땐, Immutable이다.
  • 특정 구현체를 생성하고 싶을 경우 생성자를 사용한다.

컬렉션 반복하기

fun main() {
    //iterator
    val iterator = currencyList.iterator()
    while (iterator.hasNext()) {
        println(iterator.next())
    }

    println("==================")

    //for 문
    for (currency in currencyList) {
        println(currency)
    }

    println("==================")

    currencyList.forEach { //인라인 함수
        println(it)
    }
     */

    //for loop -> map
    val lowerList = listOf("a", "b", "c")
    /*
    val upperList = mutableListOf<String>()
    for(lowerCase in lowerList){
        upperList.add(lowerCase.uppercase())
    }
     */
    val upperList =
        lowerList.map { it.uppercase() } //map, filter 와 같은 인라인 함수를 사용해 개발자가 직접 코드를 작성하지 않아도 된다
    //println(upperList)

    /*
    val filterList = mutableListOf<String>()
    for(upperCase in upperList){
        if(upperCase == "A" || upperCase == "C"){ // a, c 만 filter를 통해 값을 넣고 싶다
            filterList.add(upperCase)
        }
    }
     */

    //val filterList = upperList.filter { it == "A" || it == "C" }
    //java8 stream 과 인라인 함수의 차이 : 자바8 stream은 터미널 오퍼레이터로, 최종 연산자가 실행이 되어야지만, 실행이 되지만 코틀린은 바로 실행이 된다.
    //val filterList = upperList.stream().filter { it == "A" || it == "C" }.collect(Collectors.toList())
    /*
    val filterList = upperList
        .asSequence() //자바8의 stream()과 같은 역할을 한다고 보면된다.
        .filter { it == "A" || it == "C" }
        .toList() //최종적으로 toList가 실행이 되어야지 모든 연산이 실행이된다
    */
    //만약 대량의 데이터를 filter를 통해 만들게 된다면, 매번 인라인 함수를 사용할 떄마다 list를 만들기 떄문에 많은 리스트에 의해 OOM이 발생할 수도 있다.
    val filterList = upperList
        .asSequence()
        .filter { it == "A" || it == "C" }
        .filter { it == "A" }
        .filter { it == "A" }
        .filter { it == "A" }
        .filter { it == "A" }
        .toList()
    println(filterList)
}
  • 코틀린 컬렉션은 Iteratable 구현체이므로 순차적 반복이 가능하다.
    • 자바에서 foreach를 사용하면 iterable를 구현한 컬렉션을 반복할 수 있다.
    • 코틀린은 for loop를 사용하면 암시적으로 이터레이터를 사용하기 때문에 좀 더 쉽게 반복할 수 있다.
  • 코틀린 표준 라이브러리에는 자주 사용되는 패턴인 forEach, map, filter와 같은 인라인 함수를 제공한다.
  • 자바 8 스트림과 비교
    • 자바 8 스트림 : 중간 연산자(map,filter, flatMap...)만 사용했을 때는 아무런 동작하지 않고, 최종 연산자(terminal operator)를 사용해야 동작한다
    • 코틀린 : 일반적인 인라인 함수가 동작할 때마다, 조건에 맞는 컬렉션을 반환하고, asSequence를 사용할 때에만, Lazy로 동작해 최종 연산자를 사용해야 동작한다.
    • 일반적으로 인라인 함수가 빠르기 때문에 인라인 함수를 쓰고 대량을 데이터를 다룰때는 OOM이 발생할 수 있으므로 시퀀스 API를 사용하자.

 

728x90

'실무 프로젝트로 배우는 Kotlin & Spring > 코틀린 고급' 카테고리의 다른 글

제네릭  (0) 2022.10.16
확장 함수  (0) 2022.10.09
실드 클래스  (0) 2022.10.09
싱글톤과 동반객체  (0) 2022.10.09
데이터 클래스  (0) 2022.10.08