ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 6장 - 코틀린 타입 시스템
    Kotlin/코틀린인액션요약 2022. 9. 16. 00:01
    728x90

    6장에서 다루는 내용

    - null이 될 수 있는 타입과 null을 처리하는 구문의 문법

    - 코틀린의 원시 타입 소개와 자바 타입과 코틀린 원시 타입의 관계

    -  코틀린 컬렉션 소개와 자바 컬렉션과 코틀린 컬렉션의 관계

     

    null 가능성

    NPE를 피할 수 있게 돕는 코틀린 타입 시스템의 특성입니다.

    컴파일 시점에 널이 될 수 있는 값들을 검사함으로 런타임 시점에 발생할 수 있는 예외의 가능성을 줄일 수 있습니다.

     

    자바와의 가장 중요한 차이로 널이 될 수 있는 타입을 명시적으로 지원합니다.

    물론 자바에서도 Optional을 사용하면 되지만 코틀린에서는 ?하나로 해결할 수 있습니다.

     

    Type? = Type 또는 null

     

    안전한 호출 연산자 ?.  // 엘비스 연산자를 활용해 null 다루기

    fun main() {
        var x : String? = null
        println(x?.length) //null 출력됨
        println(x?.length?:0) //0 출력됨
    }

    ?. 연산자를 이용하면 x가 null이면 length가 호출되지 않고 null이 나오게 됩니다

    ?: 연산자를 이용하면 x가 null이면 기본값으로 0을 출력합니다.

     

    안전한 타입 캐스트 as?

    as? 는 값을 대상 타입으로 변환할 수 없으면 null을 반환합니다.

    is와 다르게 if문을 작성하지 않아도 되며 코드가 간결해집니다.

     

    널 아님 단언: !!

    null이 될 수 없다는 의미로 사용합니다.

    그냥 쓰지 않는 것을 권장합니다.

     

    let 함수

    let 함수를 사용하면 null이 될 수 있는 식을 더 쉽게 다룰 수 있습니다.

     

    가장 흔하게 사용되는 예시로 null이 될 수 있는 값을 null이 아닌 값만 인자로 받는 함수로 넘기는 경우입니다.

     

    fun sendEmailTo(email : String) {}

    위의 함수로 널이 될 수 있는 타입의 값을 넘길 수 없습니다.

     

    하지만 let을 이용하면 인자를 전달할 수 있습니다.

    fun main() {
        val email: String? = null
        email?.let {email -> sendEmailTo(email)}
    }
    
    fun sendEmailTo(email : String){
        println("send to ${email}")
    }

    email은 null 이여서 아무 일도 일어나지 않습니다.

     

    나중에 초기화할 프로퍼티

    객체 인스턴스를 일단 생성한 다음 나중에 초기화하는 프레임워크가 많이 있습니다.

    코틀린에서는 lateinit 키워드를 사용해서 프로퍼티를 나중에 초기화할 수 있습니다.

     

    이때 나중에 초기화하는 프로퍼티는 항상 var이여야 합니다.

     

    코틀린의 원시 타입

    코틀린은 원시 타입과 래퍼 타입을 구분하지 않습니다.

     

    하지만 실행 시점에 숫자 타입은 가능한 한 가장 효율적인 방식으로 표현됩니다.

     

    대부분의 경우 코틀린의 Int 타입은 자바 int 타입으로 컴파일됩니다.

     

    하지만 널이 될 수 있는 원시 타입으로 Int?, Boolean? 등을 사용하면 원시 타입으로 컴파일되지 않고 래퍼 타입으로 컴파일됩니다.

     

    마찬가지로 컬렉션을 사용하거나 제너릭을 사용하면 래퍼 클래스로 컴파일됩니다.

     

    숫자 변환

    다른 타입의 숫자로 자동 변환하지 않습니다.

    예를 들어 Long -> Int 조차 불가능합니다.

     

    직접 명시적으로 변환 메서드를 호출해야 합니다.

     

    Any 최상위 타입

    자바의 Object 클래스처럼 Any 타입은 모든 널이 될 수 없는 타입의 조상 타입입니다.

    반대로 모든 널이 될 수 있는 타입의 조상은 Any?입니다.

     

    코틀린의 void : Unit 타입

    자바 void와 같은 기능을 합니다.

     

    그러면 자바의 void와 어떤 차이점이 있을까요?

    void와 달리 Unit을 타입 인자로 쓸 수 있습니다.

    Unit 타입의 함수는 Unit 값을 묵시적으로 반환하며 이 특성은 제너릭 파라미터를 반환하는 함수를 오버라이드 하면서 반환 타입으로 Unit을 사용할 때 유용합니다.

     

    자바에서는 return null을 사용해야 합니다.

    함수형 프로그래밍에서 Unit은 '단 하나의 인스턴스만 갖는 타입'을 의미해왔기 때문에 이러한 이름을 채택했다고 합니다.

     

     

    Nothing 타입

    Nothing 타입은 아무 값도 포함하지 않습니다.

     

    함수가 정상적으로 끝나지 않을 때 Nothing을 사용합니다.

     

    예를 들어 테스트 라이브러리들이 fail 함수를 제공할 때 사용됩니다.

    fun fail(message: String) : Nothing{
    	throw IllegalStateException(message)
    }

     

    컬렉션과 배열

    널이 될 수 없는 값, 널이 될 수 있는 값을 구분하여 컬렉션을 다룰 수 있습니다.

     

    표준 라이브러리로 filterNotNull이라는 함수를 제공하여 null이 될 수 있는 값을 걸러내 주는 역할을 수행합니다.

     

    읽기 전용 컬렉션과 변경 가능한 컬렉션

    val, var의 구별과 마찬가지로 컬렉션도 읽기 전용과 변경 가능한 컬렉션을 구분합니다.

     

    하지만 같은 컬렉션 객체를 가리키는 다른 타입의 참조들이 있을 수 있습니다.

     

    예를 들어 a, b, c라는 컬렉션을 읽기 전용과 변경 가능한 리스트가 참조로 가지고 있을 수 있습니다.

     

    이런 상황에서는 읽기 전용 컬렉션이 항상 thread safe 하지 않습니다.

    val a : MutableList<String> = mutableListOf("a","b")
    val list : List<String> = a
    val mutableList : MutableList<String> = a
    
    fun main() {
        mutableList.add("change")
        println(list) //결과 [a, b, change]
    }

     

     

    댓글

Designed by Tistory.