본문 바로가기

Dev Book/Kotlin IN ACTION

CH6(6.1-2). 널 가능성

1. 나중에 초기화할 프로퍼티

- 객체 인스턴스를 일단 생성한 다음에 나중에 초기화하는 프레임워크가 많다. 하지만 코틀린에서는 클래스 안의 널이 될 수 없는 프로퍼티를 생성자 안에서 초기화하지 않고 특별한 메소드 안에서 초기화할 수는 없다. 일반적으로는 생성자에서 모든 프로퍼티를 초기화하며, 만약 프로퍼티 타입이 널이 될 수 없는 타입이라면 반드시 널이 아닌 값으로 초기화해야 한다. 그럴 수 없다면 널이 될 수 있는 타입을 제공해야 하거, 이 경우 모든 프로퍼티 접근에 널 검사를 넣거나 !!를 넣어야하므로 보기 나쁜 코드가 된다.

- lateinit 변경자를 붙이면 프로퍼티를 나중에 초기화할 수 있다.

 

class MyService{
    fun performAction():String = "action"
}
class MyTest{
    private lateinit var myService:MyService //초기화하지 않고 널이 될 수 없는 프로퍼티로 선언
    @Before fun setUp(){
        myService = MyService() //진짜 초깃값 지정
    }

    @Test fun testAction(){
        Assert.assertEquals("action", myService.performAction()) //널 검사를 수행하지 않고 프로퍼티 사용
    }
}

 

- 나중에 초기화하는 프로퍼티는 항상 var여야 한다. val의 경우 final 필드로 컴파일되며, 생성자 안에서 반드시 초기화 해야 한다.

2. 널이 될 수 있는 타입 확장

fun verifyInput(input:String?){
    if(input.isNullOrBlank()){ //안전한 호출을 하지 않아도 된다.
        println("Please fill in the required fields")
    }
}

 >>>verifyInput(" ")
 Please fill in the rquired fields
 >>>verifyInput(null)
 Please fill in the rquired fields

 

- 널이 될 수 있는 타입의 값에 대해 널이 될 수 있는 타입의 확장 함수를 호출할 시, 안전한 호출(?.)을 사용하지 않고도 호출 가능하다.

3. 타입 파라미터의 널 가능성

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

 

fun <T> printHashCode(t:T){
    println(t?.hashCode()) //t가 널이 될 수 있으므로 안전한 호출 사용.
}

 

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

 

fun <T> printHashCode2(t:T){ //이제 T는 널이 될 수 없는 타입.
    println(t.hashCode())
}

 

printHashCode2(null)에 대해 Null can not be a value of a non-null type TypeVariable(T)와 같은 컴파일 오류가 발생한다.

 

- 타입 파라미터는 널이 될 수 있는 타입을 표시하려면 반ㄷ시 ?를 타입 이름 뒤에 붙여야 한다는 규칙의 유일한 예외다.

4. 널 가능성과 자바

- 널 가능성을 지원하지 않는 자바를 코틀린과 조합해서 사용할 시 상호운용성을 어떻게 향상시킬 수 있을까?

- 첫번째로 자바 코드에 애노테이션으로 표시된 널 가능성 정보를 활용한다. @Nullable String은 String?과, @NotNull String은 String과 같다.

- 애노테이션이 소스 코드에 없는 경우 자바의 타입은 코틀린의 플랫폼 타입이 된다. 플랫폼 타입은 코틀린이 널 관련 정보를 알 수 없는 타입을 말한다. 그 타입을 널이 될 수 있는 타입으로 처리하든, 널이 될 수 없는 타입으로 처리하든 개발자의 몫이며 컴파일러는 모든 연산을 허용한다. 자바 api를 다룰 때는 자바 메소드가 널을 반환할 지 알아내고 널을 반환하는 메소드에 대한 널 검사를 추가해야 한다.(모든 자바 타입을 널이 될 수 있는 타입으로 다루지 않은 이유는 결코 널이 될 수 없는 값에 대해서 불필요한 널 검사가 들어가지 않도록 하기 위해서다.) 

- 코틀린에서는 플랫폼 타입을 선언할 수 없다. 자바에서 가져온 타입만 플랫폼 타입이 된다.

 

 

'Dev Book > Kotlin IN ACTION' 카테고리의 다른 글

CH6(6.3). 컬렉션과 배열  (0) 2022.02.06
CH6(6.2). 코틀린의 원시 타입  (0) 2022.01.21
CH6(6.1-1). 널 가능성  (0) 2022.01.16
CH5(5.5). 수신 객체 지정 람다  (0) 2022.01.08
CH5(5.3). 지연 계산 컬렉션 연산  (0) 2022.01.02