ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 코틀린 타입 시스템 - null 관련
    Kotiln 2019. 7. 19. 16:05

    null 가능성(nullability) 은 NullPointerException 오류를 피할 수 있게 돕기 위한 코틀린 타입 시스템의 특성이다.

    null이 될 수 있는 타입

    변수의 타입 뒤에 ? 를 붙이면 null 참조를 저장할 수 있다는 뜻이다.

    var x: String? = null

    ?. 안전한 호출 연산자

    ?. 연산자는 null 검사와 메소드 호출을 한번의 연산으로 수행한다.

    var allCaps: String? = s?.toUpperCase()

    ?: 엘비스 연산자

    null 대신 사용할 디폴트 값을 지정할 때 사용한다.

    var str: String = s ?: "" // s가 null 이면 빈 문자열("")이다

    as? 안전한 캐스트

    값을 대상 타입으로 변환할 수 없으면 null을 반환한다.

    var foo = bar as? String

    일반적으로 엘비스 연산자와 함께 사용한다.

    var foo = bar as? String ?: ""

    !! null 아님 단언 (not-null assertion) 연산자

    어떤 값이든 null이 될 수 없는 타입으로 강제로 바꿀 수 있다.
    null 에 대해 !! 를 적용하면 NullPointerException 이 발생한다.

    let 함수

    안전한 호출 연산자 (?.) 와 함께 사용하여 원하는 식의 결과가 null 이 아닐 때 수행하는 로직이 있을 때 사용한다.

    foo?.let{ ... it ... }

    foo != null 이면 it 은 람다 안에서 null 이 아니다.
    foo == null 이면 아무 일도 일어나지 않는다.

    나중에 초기화할 프로퍼티

    코틀린에서는 클래스 안의 null 이 될 수 없는 프로퍼티를 생성자 안에서 초기화하지 않고 특별한 메소드 안에서 초기화할 수 없다.
    lateinit 변경자를 붙여서 프로퍼티를 나중에 초기화할 수 있다.
    나중에 초기화하는 프로퍼티는 항상 var 여야 한다 .
    초기화하기 전에 프토퍼티에 접근하면 예외가 발생한다.

    null이 될 수 있는 타입 확장

    null이 될 수 있는 타입에 대한 확장 함수를 정의하면 null 값을 다루는 강력한 도구로 활용할 수 있다.
    예로 String? 타입의 수신 객체에 대해 호출할 수 있는 isNullOrEmpty 나 isNullOrBlank 메소드가 있다.

    var str: String? = null
    if(str.isNullOrBlank()){
        println("str is Null or Blank")
    }

    안전한 호출 없이도 null이 될 수 있는 수신 객체 타입에 대해 선언된 확장 함수를 호출 가능하다.

    isNullOrBlank 함수는 내부적으로 다음과 같이 정의되어 있다.

    fun String?.isNullOrBlank() : Boolean = 
        this == null || this.isBlank()

    타입 파라미터의 null 가능성

    코틀린에서는 함수나 클래스의 모든 타입 파라미터는 기본적으로 null이 될 수 있다.
    타입 파라미터 T 를 클래스나 함수 안에서 타입 이름으로 사용하면 이름 끝에 ? 가 없더라도 T 가 null이 될 수 있는 타입이다.

    fun <T> printHashCode(t: T){
        println(t?.hashCode())
    }
    
    printHashCode(null)

    타입 파라미터가 null이 아님을 확실히 하려면 null이 될 수 없는 타입 상한(upper bound) 을 지정해야 한다.
    타입 상한을 지정하면 null이 될 수 있는 값을 거부하게 된다.

    fun <T: Any> printHashCode (t: T){
        println(t.hashCode())
    }
    
    printHashCode(null)    // error
    printHashCode(42)        // ok

    null 가능성과 자바

    자바코틀린
    @Nullable StringString?
    @NotNull StringString

    자바에서 null 가능성 애노테이션이 없는 경우 코틀린의 플랫폼 타입이 된다.

    플랫폼 타입

    코틀린이 null 관련 정보를 알수 없는 타입을 말한다.
    그 타입을 null이 될 수 있는 타입으로 처리해도 되고 null이 될 수 없는 타입으로 처리해도 된다.
    null 이 될 수 없는 타입에 null 이 들어가는 경우 NullPointerException이 발생한다.
    코틀린에서 플랫폼 타입을 선언할 수는 없으며 자바 코드에서 가져온 타입만 플랫폼 타입이 된다.
    하지만 IDE나 컴파일러 오류 메시지에서는 플랫폼 타입을 볼 수 있다.

    val i: Int = person.name
    
    > Error: Type mismatch: inferred type is String! but Int was expected

    코틀린 컴파일러가 표시한 String! 라는 타입은 자바 코드에서 온 타입니다.
    ! 표기는 String! 타입의 null 가능성에 대해 아무 정보도 없다는 뜻이다.

    상속

    코틀린에서 자바 메소드를 오버라이드 할 때 그 메소드의 파마리터와 반환 타입을 null 이 될 수 있는 타입으로 선언할지 null 이 될 수 없는 타입으로 선언할지 결정해야 한다.

    구현 메소드를 다른 코틀린 코드가 호출할 수 있으므로 코틀린 컴파일러는 null 이 될 수 없는 타입으로 선언한 모든 파라미터에 대해 null 이 아님을 검사하는 단언문을 만들어준다.
    자바 코드가 그 메소드에게 null 값을 넘기면 이 단언문이 발동돼 예외가 발생한다. 파라미터를 메소드 안에서 결코 사용하지 않아도 이런 예외는 피할 수 없다.

    참고 도서 : Kotlin in Action (2017)

    반응형

    댓글 0

Designed by Tistory.