Kotlin - nullable variable

2023. 12. 15. 16:39프로그래밍 언어/Kotlin

안드로이드 스튜디오 개발자 페이지를 기반으로 작성됨.

https://developer.android.com/courses/pathways/android-basics-compose-unit-1-pathway-1?hl=ko

 

Kotlin 프로그래밍 소개  |  Android Basics Compose - First Android app  |  Android Developers

Kotlin에서 Android 앱 빌드를 준비하기 위해 Kotlin의 입문 프로그래밍 개념을 알아봅니다.

developer.android.com

 

이번 블로그에서는 Kotlin에서 지원하는 nullable variable에 대해서 소개해보고자 한다.

 

우선 null이라는 것을 먼저 설명할 필요가 있는데,

 

null이라는 것은 변수 안에 값이 비어 있는 상태이다.

 

String type 변수에 가령 아래와 같이 자신이 가장 좋아하는 지역을 저장할 수 있다.

 

val favoriteLocation: String = "HollyWood"

 

하지만, 만약에 자신이 좋아하는 지역이 없으면 어떻게 해야할까??

 

None이라는 변수를 저장해야 할까? 아니면 없음을 의미하는 다른 String type의 변수를 저장해야 할까?

 

답은 아니다. 이렇게 저장할 경우 컴파일러는 favoriteLocation이 없는 것이 아니라 None 혹은 다른 변수 값을 가진 변수로 해석하게 된다.

 

이럴 때 사용하는 값이 null 값이다. 변수에 값이 없음을 나타낸다.

 

그래서 우리가 처음에 "HollyWood" 라는 지역의 변수를 저장했다가 null이라는 값으로 변경하는 것이 가능할까?

 

val favoriteLocation: String = null
// Null can not be a value of a non-null type String

 

위와 같이 null 값을 대입해보면 아마도 주석처리된 것과 같은 오류 메세지를 얻을 수 있을 것이다.

 

Kotlin에서는 그래서 null을 허용하는 유형의 데이터와 null을 허용하지 않는 유형의 변수를 나누어 놓았다.

 

null을 허용하지 않는 변수의 경우 우리가 흔히 쓰는 Data type으로 말 그래도 null을 허용하지 않는다.

 

반대로 null을 허용하는 변수의 경우 기존 데이터 타입을 포함해서 null 값을 저장하는 것을 허용하는 변수이다. 

가령, String data type에서 null을 허용하는 변수는 기존 "HollyWood" 같은 리터럴 string data도 허용을 하고 데이터가 없음을 나타내는 null도 허용한다.

 

null을 허용하는 변수는 다음과 같이 데이터 타입 뒤에 ? 를 추가로 기입하여 나타낼 수 있다.

 

var favoriteLocation: String? = "HollyWood"
favoriteLocation = null

 

위와 같이 String 뒤에 ? 를 기입함으로써 null 허용 가능 변수를 만들어 주었고, null 값을 저장해도 오류 메세지가 나타나지 않는 것을 확인할 수 있을 것이다.

 

null을 허용하는 변수가 장점이 될 수 있는 이유가, null을 허용하지 않는 변수만 존재할 경우 런타임에서 null 값이 생기면 바로 Null Point Exception 에러가 발생하게 된다. 즉, null 값이 생기면 프로그램이 바로 다운되는 것이다.

 

하지만 null을 허용하는 변수가 있는 경우, null 값이 생길만한 지점에 예외 처리나 적절한 논리를 구축하여 원하지 않는 프로그램 종료를 막을 수 있는 것이다.

 

이러한 이유로 인해 Kotlin에서 지원하는 nullable 변수가 용이하게 사용될 수 있는 것이고, 이제는 nullable 변수의 멤버 혹은 메서드 접근에 대해서 살펴보자.

 

안전 호출 연산자 & 어설션 연산자

 

우리가 보통 선언하는 변수들은 특정 데이터 타입 클래스의 객체이다. 

 

String data type의 객체들은 문자열의 길이를 나타내는 length라는 속성을 가지고 있고 이를 null값과  null이 아닌 값에 대해서 사용해보도록 하자.

 

var favoriteLocation: String = "HollyWood"
println(favoriteLocation.length)
// 9

var favoriteLocation: String? = "HollyWood"
println(favoriteLocation.length)
// Error message occur

 

 

위에 선언한 String data type의 속성을 접근하려고 하면 정상적으로 잘 접근이 된다.

 

하지만, nullable data type의 속성에 접근하려고 하면, 컴파일 자체가 안된다. 그 이유는 favoriteLocation이라는 nullable data가 null일 가능성을 고려하여 null 값에는 속성이 존재하지 않기 때문에 컴파일 할 때 에러를 발생시키는 것이다.

이것을 null 참조라고 한다. 컴파일러가 컴파일 당시에 오류를 발생하기 때문에 런타임 에러를 방지할 수 있는 장점이 있다.

 

이제, nullable 변수의 속성 및 메서드에 접근하는 방법을 알아볼 것인데, 2가지 방법이 있다.

 

안전 호출 연산자

 

먼저, 안전 호출 연산자 ? 이다. 우선 사용하는 방법에 대해서 먼저 확인해보자.

 

var favoriteLocation: String? = "HollyWood"
println(favoriteLocation?.length)
// 9

favoriteLocation = null
println(favoriteLocation?.length)

 

nullable 변수 뒤에 ?를 붙이고 . 연산자를 수행하는 것이다. 안전 호출 연산자를 수행했기 때문에 변수 값이 null인 경우 속성 및 메서드에 대한 반환을 null로 지정하고, null 이 아닌 경우에는 정상적으로 속성 및 메서드에 대한 값을 반환한다.

 

어설션 연산자

 

nullable 변수에 접근하는 또 다른 방법은 어설션 연산자 !! 를 사용하는 것이다.

 

이 연산자는 해당 변수가 null이 아닌 값이라고 가정하고 변수에 접근하는 연산으로 만일 변수 값이 null이라면 런타임 도중에 에러가 발생하여 프로그램이 종료된다.

 

var favoriteLocation: String? = "HollyWood"
println(favoriteLocation!!.length)
// 9

favoriteLocation = null
println(favoriteLocation!!.length)
// NullPointException Error

 

따라서 웬만하면 어설션 연산자를 안쓰는 것이 좋으며, 사용할 경우 적절한 예외 처리를 통해 프로그램이 예기치 못하게 종료되는 것을 방지해야 한다.

 

위와 같은 연산자를 제외하고도 직접적으로 nullable 변수에 접근하는 방법이 있는데, 이는 조건문을 함께 활용하는 것이다. 코드를 살펴보자.

 

var favoriteLocation: String? = "HollyWood"

if (favoriteLocation != null) { 
    // null이 아닌 경우
    print("Length of my FavoriteLocation is ${favoriteLocation.length}")
} else {
    // null인 경우
    print("Length of my FavoriteLocation is 0")
}

 

조건문을 통해 nullable 값이 null인지 아닌지 확인하여 null이 아닌 경우에는 변수에 직접적으로 액세스할 수 있고 아닌 경우에 적절한 로그를 출력하도록 만들 수 있다.

 

if/else 문을 표현식으로 바꾸어서 위와 같은 코드를 다음과 같이 변경할 수도 있다.

 

val favoriteLocation: String? = "HollyWood"

val lengthOfLocation = if (favoriteLocation != null) {
    favoriteLocation.length
} else {
    0
}

println("Length of My FavoriteLocation is ${lengthOfLocation}")

 

 

Kotlin에서는 위와 같은 조건문을 표현식으로 바꿀 때 조금 더 간결하게 표현할 수 있는 Elvis 연산자를 제공한다. 이 연산자는 값이 null일 경우와 아닐 경우를 나누어서 간략하게 표기할 수 있도록 문법을 제공한다.

 

val favoriteLocation: String? = "HollyWood"

val lengthOfLocation = favoriteLocation?.length ?: 0

println("Length of My Favorite Location is ${lengthOfLocation}")

 

다만 위와 같이 변수에 직접적으로 접근하는 것이 아닌 안전 호출 연산자를 통해 변수에 접근할 수 있다.

favoriteLocation이 null이 아닐 경우 해당하는 속성을 lengthOfLocation  변수에 저장하고 null 일경우 null을 저장하는 형태이다. 

 

nullable variable ?. method/property ?: default value

 

위와 같은 형태로 표기할 수 있다.

'프로그래밍 언어 > Kotlin' 카테고리의 다른 글

Kotlin - Generic  (1) 2024.01.30
Kotlin - 람다 표현식  (0) 2023.12.18
Kotlin - 클래스  (1) 2023.12.18
Kotlin - 조건문  (0) 2023.12.13
Kotlin 기초 문법  (2) 2023.11.28