[Kotlin] null 값에 대한 안정적인 처리: Null Safety
Kotlin은 null 값의 처리에 많은 공을 들인 언어이다.
null로 인해 프로그램 전체, 혹은 앱 전체가 멈출 수 있는 것 때문에 null은 항상 이슈의 중심에 있다.
프로그램이 멈출 수 있는 상황을 다음과 같이 코드로 만들어보겠다. (1개의 메서드를 갖고 있는 클래스를 만든다.)
class One {
fun print() {
Log.d("null_safety", "can you call me?")
}
}
그리고 onCreate() 메서드 안에서 다음과 같이 one 변수 하나를 선언하고 타입으로 내가 만든 클래스를 지정해둔다.
그리고 특정 조건이 만족할 때만 선언한 변수에 생성자를 호출해서 저장해두는 조건문 if를 만든다.
그리고 변수를 통해 해당 클래스의 메서드를 하나 호출한다.
var one: One
if (1 > 2){
one = One()
}
one.print()
위 코드에서는 1 > 2가 false이기 때문에 one 변수는 아무것도 없는 null 상태가 된다.
이 때 print 메서드를 호출하면 null 포인터 예외가 발생하면서 프로그램이 다운된다.
물론 위 코드는 안드로이드 스튜디오에서 오류를 발생 시켜 컴파일되지 않도록 막아준다.
하지만 코드의 양이 많아지면 이런 상황이 언제든지 발생할 수 있으며 Kotlin은 이런 상황을 방지하기 위해서 다양한 안전장치를 만들어 두었다.
그 결과물이 Null Safety이다!
1) null 값 허용하기: ?
Kotlin에서 지정하는 기본 변수는 모두 null이 입력되지 않는다.
null 값을 입력하기 위해서는 변수를 선언할 때 타입 뒤에 ?(Nullable, 물음표)를 입력한다.
var variable: String?
변수에 null 허용 설정하기
변수의 타입 뒤에 물음표를 붙이지 않으면 null 값을 입력할 수 없다.
null 예외를 발생시키고 싶지 않다면 기본형으로 선언한다.
var nullable: String? // 타입 다음에 물음표를 붙여서 null 값을 입력할 수 있습니다.
nullable = null
var notNullable: String
notNullable = null // 일반 변수에는 null을 입력할 수 없습니다.
함수 파라미터에 null 허용 설정하기
안드로이드의 onCreate() 메서드의 Bundle 파라미터처럼 함수의 파라미터에도 null 허용 여부를 설정할 수 있다.
함수의 파라미터가 null을 허용하려면 해당 파라미터에 대해서 null 체크를 먼저 해야만 사용할 수 있다.
fun nullParameter(str: String?){ // 파라미터 str에 null이 허용됨
if (str != null) { // null 체크를 해야 str 사용가능
var length2 = str.length
}
}
- 위 코드처럼 str 파라미터를 조건문 if에서 null인지 아닌지 체크해야지만 사용할 수 있다.
함수의 리턴 타입에 null 허용 설정하기
- 함수의 리턴 타입에도 물음표를 붙여서 null 허용 여부를 설정할 수 있다.
fun nullReturn(): String? {
return null
}
- 함수의 리턴 타입에 Nullable이 지정되어 있지 않으면 null 값을 리턴할 수 없다.
2) 안전한 호출: ?.
변수를 Nullable로 만들기 위해서 물음표를 사용했다.
이제는 ?.(Safe Call, 물음표와 온점)을 사용해서 null 체크를 좀 더 간결하게 하겠다.
Nullable인 변수 다음에 ?.을 사용하면 해당 변수가 null일 경우 ?. 다음의 메서드나 프로퍼티를 호출하지 않는다.
다음 코드에서처럼 문자열의 길이를 반환하는 length 프로퍼티를 호출했는데 str 변수 자체가 null일 경우 length 프로퍼티를 호출하지 않고 바로 null을 반환한다.
fun testSafeCall(str: String?): Int? {
// str이 null이면 length를 체크하지 않고 null을 반환합니다.
var resultNull: Int? = str?.length
return resultNull
}
- 만약 Safe Call을 사용하지 않았는데 str 변수가 null이라면 프로그램은 다운된다.
3) Null 값 대체하기: ?:
위에서 안전한 호출을 위해서 ?. (Safe call)을 사용했다.
이제는 ?: (Elvis Operator, 물음표와 콜론)을 사용해서 원본 변수가 null일 때 넘겨줄 기본값을 설정해보겠다.
다음 코드에서 Safe Call 다음에 호출되는 프로퍼티 뒤에 다시 ?:을 붙였다.
그리고 0이라는 값을 표시했다.
이렇게 호출하면 str 변수가 null일 경우 가장 뒤에 표시한 0을 반환한다.
fun testElvis(str: String?): Int {
// length 오른쪽에 ?:을 사용하면 null일 경우 ?: 오른쪽의 값이 반환됩니다.
var resultNonNull: Int = str?.length ?: 0
return resultNonNull
}
여기서 잠깐!
Nullable(?), Safe Call(?.), Elvis Operator(?:)를 구분하는 법
Nullable
표기법: 선언하는 변수의 타입 다음에 ? 표기
사용 목적: null을 입력받기 위해 사용
사용 예: var nullable: 타입?
Safe Call
표기법: 선언된 변수의 이름 다음에 ?. 표기
사용 목적: null일 때 ?. 다음에 나오는 속성이나 명령어를 처리하지 않기 위해 사용
사용 예: var result = 변수?.length 또는 변수?.프로퍼티?.something
Elvis Operator
표기법: 선언된 변수의 이름 다음에 ?: 표기
사용 목적: null일 때 ?: 다음에 나오는 값을 기본값으로 사용
사용 예: var result = 변수?:0 또는 변수?.프로퍼티?:0