본문 바로가기

[Kotlin] 기본 - Null 처리 '? / ?. / !! / ?: / lateinit / lazy'

Kotlin, Null 처리

 

 

Null 허용 (? 연산자) 

코틀린(Kotlin)에서는 기본적으로 Null값을 허용하지 않으므로, 기본적으로는 모든 객체가 생성과 동시에 값을 초기화 필요

초기화하지 않아 에러가 발생하는 예시

val a :String	// Error, 초기화 필요


Null 값으로 초기화해서 에러 발생하는 예시

val a :String = null	// Error, 기본적으로 Null값 허용 x 

 

? 키워드 - @Nullable

변수의 자료형 오른쪽에 ? 연산자를 명시적으로 사용하면, 해당 변수는 Null값을 허용하는 의미로 에러 미발생

val a :String? = null	// OK, ? 키워드로 @Nullable 의미

 

 

안전한 호출 (?. 연산자)

?. 연산자Null Safe operator의 의미
메서드 호출 시 점(.) 연산자 대신 (?.)를 사용하면 해당 변수/객체가 Null이 아닌 경우에만 호출
{ 변수/객체?.메서드() } 형식으로 사용, 해당 변수/객체가 Null이 아니면 메서드를 호출하고, Null이면 null을 반환

Null이 아닐때 메서드 호출결과
   str.toUpperCase()   // TEST CODE, 대문자로 변환

Null일때 메서드 호출 결과
   str2?.toUpperCase()    // null 반환


안전한 호출 '?.'키워드를 사용하면 if문을 정말 간단하게 줄여서 사용이 가능

val str :String? = null

// str이 null이 아닌지 검사, true면 메서드 호출, 아니면 null 반환
println(if (str != null) str.toUpperCase() else null)
println(str?.toUpperCase())

 

 

엘비스 연산자 (?:)

안전한 호출(?.)null이 아닌 사용자 정의값을 반환하고 싶을 때 (?:)엘비스 연산자를 함께 사용.
기본적으로 안전한 호출(?.)에서 null이면 null을 반환, 그 반환값을 지정해주는 연산자

null이 아니면 "초기화하시오"를 출력하는 예시
ex) if ( str != null ) str.toUpperCase() else "초기화하시오." - 동일한 방법

val str :String? = null

// 기본 안전한 호출만 사용시
println(str?.toUpperCase())	// null 출력

// str이 null이 아니면 toUpperCase() 호출, null이면 ?: 연산자 뒤를 호출
println(str?.toUpperCase() ?: "초기화하시오." // "초기화하시오." 출력

 

 

Null값이 아님을 보증 (!!)

@NotNull 의미로 해당 변수가 Null값이 아님을 보증해줘서 null값이 허용되는 변수를 대입할 수 있도록 하는 연산자(!!)

val name :String? = "김루피"	// Null일수도 있는 변수에 "김루피" 할당

val name2 :String = name	// Error, name은 Null일수 있기에 에러 발생

val name3 :String? = name	// OK, name3도 Nullable한 변수이기에 할당 가능

val name4 :String = name!!	// OK, name!!로 name이 null이 아님을 보증

만약 (!!)연산자로 null이 아님을 보증했지만 null값이라면 실행시 NPE예외 발생

 

 

늦은 초기화 - lateinit

변수/객체의 값을 나중에 초기화할 경우가 필요할 때 사용하는 키워드(lateinit)
변수선언 앞부분에 추가하여 사용 { lateinit var 변수명 :자료형 } 방식으로 늦은 초기화 선언 후 나중에 초기화를 진행

초기화를 하지 않고 변수를 접근하면 null 값을 참조하게 되면서 NPE예외로 앱종료 발생

// 기본 변수 사용
var a :String	// Error, 초기화 필요

// lateinit 키워드 사용
lateinit var str :String

println("%{str} 출력결과")	// Error, NPE예외 발생 (Null 참조)

str = "TEST"
println("%{str} 출력결과")	// "TEST 출력결과" 출력

 

lateinit 키워드 사용 조건

    - var 변수에서만 사용

    - Null 값으로 초기화 불가

    - 초기화 전에는 변수 사용 불가 (NPE예외 발생)

    - Int / Long / Double / Float 자료형은 사용 불가

 

 

늦은 초기화 - lazy

lateinit이 var변수의 늦은 초기화라면 lazy는 값을 변경할 수 없는 val(상수)에 사용하는 키워드
변수 자료형 뒤에 추가해서 사용 " val 변수명 :자료형 by lazy { 초기화 블럭 } " 사용 방식

by lazy 키워드초기화 블럭은 해당 변수가 처음 호출될때 실행되고, 그 이후 호출에는 초기화 블럭 실행 X

val str :String by lazy {
    println("초기화")		  // 함수 호출도 가능
    var temp = "test code"	
    temp.toUpperCase()		// 초기화 블럭의 마지막 값이 str에 저장되는 값
}

// str을 처음으로 호출하는 시점에 lazy 내부 초기화 블럭 수행 (1~5 Line)
println("$str")	// 초기화; TEST CODE 출력

println("$str") // TEST CODE 출력