공상하는 개발자

[Kotlin] Null 안정성 파헤치기 본문

개발/안드로이드

[Kotlin] Null 안정성 파헤치기

공상과학소설 2020. 1. 25. 19:37
반응형

발단

프로젝트를 하다가 보면 null에 대한 오류가 정말 많이 일어난다. (고통받는 1인...)

Kotlin은 특이하게 null에 대한 처리가 잘 되어있는 프로그래밍언어인데 어떤 식으로 이루어지는지 파헤쳐보자!


Non_Nullable : null이 될 수 없는 type

null 이 들어오게 된다면 컴파일에러를 발생시킴.

var nonNullable : String = "non_Nullable"
nonNullable = null  //error : Null can not be a value of a non-null type String

Nullable : null이 될 수 있는 type 

null이 들어올 수 있게 타입 선언시 ?를 붙인다.

var nonNullable : String? = "non_Nullable"
nonNullable = null //컴파일 성공

 

null 이 들어올 수 있는 타입이라면 내부에서 null check를 해줘야 한다.


(nullable) -> (non-nullable)

👉 !! 연산자 

  • 객체가 null이 아닌 것을 보장합니다.
  • 만약 !!를 붙인 객체가 null이라면 NPE를 발생시킴.
  • 그렇게 완벽하고 안정적인 방법은 아니다.

 

null safe operator (safe call 연산자로 nullable 접근)

👉 ?. 연산자

  • null을 안전하게 처리하기 위한 연산자. 
  • ?. 연산자를 사용하면, 앞의 변수가 null이 아닐 때만 오른쪽 함수가 실행되고 null이면 null을 반환
  • null 처리를 간결하고 편리하게 할 수 있는 장점이 있다.
fun main(args: Array<String>) {
    getMovieTitle(null)		//null 출력
    getMovieTitle("ABC")	//3 출력
}

fun getMovieTitle(title:String?){
    val titleLength:Int? = title?.length
    print(titleLength)
}

 

Elvis operator (엘비스 연산자)

👉 ?: 연산자

  • ?. 연산자는 좌항이 null 이면 null을 반환 했지만 ?: 연산자는 설정한 default 값을 반환할 수 있다.
  • 이름이 Elvis 인 이유는?:모양이 엘비스 프레슬리 머리스타일을 닮아서이다.
  • 우항에 return이나 throw 도 넣을 수 있다.
fun main(args: Array<String>) {
    getMovieTitle(null)		//0 출력
}

fun getMovieTitle(title: String?) {
    val titleLength: Int? = title?.length ?: 0
    print(titleLength)
}

 

Safe cast (안전 캐스트)

👉 as? 연산자

  • casting을 시도하고, casting이 불가능하면 null을 반환합니다.
fun main(args: Array<String>) {
    print(getUserAge("KCY"))	//0 출력
    print(getUserAge(26))	//26 출력
}

fun getUserAge(o: Any?): Int {
    return o as? Int ?: 0
}

 

let 함수

  • not null인 경우에만 지정된 구문을 실행해주는 함수.
  • let 함수를 통해 자신의 receiver 객체를 람다식 내부로 넘겨줌.
  • let 함수 내부에서는 receiver 객체를 it으로 받아서 표현한다.
  • null이라면 let의 람다 구문은 수행되지 않음.
fun main(args: Array<String>) {
    var Id:String? = "ghkdua1829"
    Id?.let { getUserId(it) }	//유저의 아이디는 ghkdua1829입니다. 출력
    Id = null
    Id?.let { getUserId(it) }	//아무것도 출력하지 않습니다.

}

fun getUserId(Id:String?){
    println("유저의 아이디는 $Id 입니다.")
}

 

Property의 초기화 지연 (lateinit)

보통 객체의 인스턴스를 생성한 후 초기화는 나중에 할 때가 많다. (바로 초기화하기 귀찮...@@)

이를 지원해주는 lateinit 키워드가 있다.

fun main(args: Array<String>) {
    var KCY = UserTest()
    KCY.getId()		//UninitializedPropertyAccessException 에러 발생
    KCY.setId("ghkdua1829")
    KCY.getId()		//ghkdua1829 출력
}

class UserTest {
    private lateinit var Id: String
    fun setId(id: String) {
        Id = id
    }
    fun getId(){
        println(Id)
    }
}

 

Generic의 Nullable

Generic을 사용하면 이는 무조건 nullable로 인식된다.

 


항상 null 에러에 대한 두려움이 있었는데 항상 두려워만 하고 있었지 해결하려고 하는 의지는 없었다...

하지만 이번 포스팅을 통해 null에 대한 두려움을 없애고,

좀 더 null 에러에 안전한 코드를 짤 수 있지 않을까 하는 기대감이 있다...

그럼 다음 포스팅 때 보세... 안녕~~~

모두 즐거운 설 보내세요~~(저는 배 터질 거 같네요!!)

반응형
Comments