코틀린의 변수 선언은 기본적으로 null을 허용하지 않는다.
val a: Int = 30
val b: String = "Hello"
위와 같이 올바른 변수 선언문에서 30
과 "Hello"
를 버린다면 오류이다.
val a: Int? = null
val b: Stirng? = null
이처럼 자료형 뒤에 물음표 기호(?)를 명시해야 한다.
Int vs Int?
String vs String?
Long vs Long?
.
.
뿐만 아니라 다른 자료형 모두 두 가지의 선언 방법이 있다.
null 가능한 선언들은 null일 가능성이 있기 때문에 가능성 검사를 해주어야 한다.
체크해주지 않는다면 사용할 수 없는 null인 변수에 접근하면서 발생하는 예외가 생긴다. (단순 출력은 상관없으나 널인 상태에서 연산되는 멤버에 접근할 때만)
NPE (NullPointerException)
예제를 보면서 더 자세히 알아보자.
fun main() {
var str1: String
println(str1)
}
위 코드를 실행하면 어떻게 될까? 잘못된 곳을 찾아낼 수 있나?
코드를 실행하게 되면
Kotlin: Variable 'str1' must be initialized
라는 오류가 뜰 것이다. 초기화를 해주지 않은 것이다.
fun main() {
var str1: String
str1 = "Hi"
println(str1)
}
이렇게 str1
을 초기화 해주어야 한다.
fun main() {
var str1: String
str1 = null
println(str1)
}
이 코드도 당연히 안된다. null을 사용하려면 물음표 기호를 붙어야 하기 때문이다. (kotlin은 기본적으로 null을 선언하지 않는다)
fun main() {
var str1: String?
str1 = null
println(str1)
}
세이프 콜이란 null이 할당되어 있을 가능성이 있는 변수를 검사하여 호출하도록 도와주는 연산자, 사용할 변수 이름 뒤에 ?.을 작성한다.
str1
의 길이를 알아보기 위해 아래와 같이 length
를 넣어보자.
fun main() {
var str1: String?
str1 = null
println("str1: $str1, length: ${str1.length}")
}
그럼 length
앞 점(.
)에 빨간줄이 그어진다.
(String? 형식에는 세이프콜이나 넌널 단정 기호가 허용됩니다 라는 문구를 볼 수 있다)
그 이유는 str1
이 null
일 수 있는 가능성이 존재하기 때문에 길이를 알 수 없다.
이 때 필요한게 위에서 언급한 세이프 콜과 non-null이다.
세이프 콜은 아래와 같이 ?.을 넣어준다. (없이 실행하면 NPE 발생)
fun main() {
var str1: String?
str1 = null
println("str1: $str1, length: ${str1?.length}")
}
str1
을 실행할건데 혹시라도 null
이라면 뒷 부분을 실행하지 않는다는 의미이다.
여기서 하나 더 ! non-null
println("str1: $str1, length: ${str1!!.length}")
이렇게 !!.는 무조건 null일리 없다라고 가정을 해서 오류를 무시한다.
null이더라도 체크하지 않는다.
length를 미리 판단문을 통해 확인할 수 있다. (kotlin은 if문을 한 줄에 작성 가능하다.)
fun main() {
var str1: String?
str1 = null
val len = if (str1 != null) str1.length else -1
println("str1: $str1, length: $len")
}
str1: null, length: -1
kotlin에서는 기본적으로 NotNull이고 Nullable 표현에만 '?'가 사용된다.
fun set(a: String, b: String?) {
// Do noting
}
var temp: String? = null
var size = -1
if (temp != null) {
size = temp.length
}
// 또는
var temp: String? = null
val size = if (temp != null) temp.length else -1
fun main() {
var str1 : Stirng? = "Hello"
str1 = null
println("str1: $str1 length: ${str1.length}")
//null 허용하면 length가 실행될 수 없음
}
세이프 콜
str1?.length
non-null 단정 기호 (최대한 이건 사용하지 않는 것이 좋다. NPE 발생 가능)
str1!!.length