1. 시작하기 전에
이 Codelab에서는 null 허용 여부 및 null
안전 중요성에 관해 알아봅니다. null 허용 여부는 많은 프로그래밍 언어에서 일반적으로 사용되는 개념으로, 변수에 값이 없어도 된다는 것을 의미합니다. Kotlin에서 null
안전을 보장하기 위해 null 허용 여부를 의도적으로 처리합니다.
기본 요건
- 변수,
println()
함수,main()
함수를 비롯한 Kotlin 프로그래밍 기본사항에 관한 지식 if/else
문, 불리언 표현식 등 Kotlin 조건문에 관한 지식- 변수에서 메서드와 속성에 액세스하는 방법을 포함한 Kotlin 클래스에 관한 지식
학습할 내용
null
의 정의- null을 허용하는 유형과 null을 허용하지 않는 유형의 차이점
null
안전의 정의 및 그 중요성, Kotlin이null
안전을 달성하는 방법?.
안전 호출 연산자와 null이 아닌!!
어설션 연산자와 함께 null 허용 변수의 메서드와 속성에 액세스하는 방법if/else
조건문으로null
검사를 실행하는 방법if/else
표현식을 사용하여 null을 허용하는 변수를 null을 허용하지 않는 유형으로 변환하는 방법- null을 허용하는 변수가
null
인 경우if/else
표현식 또는?:
Elvis 연산자를 사용하여 기본값을 제공하는 방법
필요한 항목
- Kotlin 플레이그라운드에 액세스할 수 있는 웹브라우저
2. null을 허용하는 변수 사용
null
의 정의
1단원에서는 변수를 선언할 때 즉시 값을 할당해야 한다는 것을 배웠습니다. 예를 들어 favoriteActor
변수를 선언할 때 즉시 "Sandra Oh"
문자열 값을 할당할 수 있습니다.
val favoriteActor = "Sandra Oh"
하지만 좋아하는 배우가 없다면 어떻게 할까요? 변수에 "Nobody"
또는 "None"
값을 할당할 수도 있습니다. 이 접근 방식은 좋지 않습니다. 프로그램에서 favoriteActor
변수에 아예 값이 없다고 해석하지 않고 "Nobody"
또는 "None"
값이 있는 것으로 해석하기 때문입니다. Kotlin에서는 null
을 사용하여 변수와 연결된 값이 없음을 나타낼 수 있습니다.
코드에 null
을 사용하려면 다음 단계를 따르세요.
- Kotlin 플레이그라운드에서
main()
함수 본문의 콘텐츠를null
로 설정된favoriteActor
변수로 대체합니다.
fun main() {
val favoriteActor = null
}
println()
함수로favoriteActor
변수의 값을 출력한 다음 이 프로그램을 실행합니다.
fun main() {
val favoriteActor = null
println(favoriteActor)
}
출력은 다음 코드 스니펫과 같습니다.
null
null
을 사용한 변수 재할당
앞에서 var
키워드로 정의된 변수를 동일한 유형의 서로 다른 값에 재할당할 수 있다고 배웠습니다. 예를 들어 새 이름이 String
유형인 경우 한 이름으로 선언된 name
변수를 다른 이름으로 재할당할 수 있습니다.
var favoriteActor: String = "Sandra Oh"
favoriteActor = "Meryl Streep"
변수를 선언한 후에 이 변수를 null
에 할당해야 하는 경우가 있습니다. 예를 들어 좋아하는 배우를 선언한 후에 이 배우를 아예 공개하지 않으려는 경우 favoriteActor
변수를 null
에 할당하면 유용합니다.
null을 허용하지 않는 변수와 null을 허용하는 변수 이해하기
favoriteActor
변수를 null
에 다시 할당하려면 다음 단계를 따르세요.
val
키워드를var
키워드로 변경한 후favoriteActor
변수를String
유형으로 지정하고 좋아하는 배우의 이름에 할당합니다.
fun main() {
var favoriteActor: String = "Sandra Oh"
println(favoriteActor)
}
println()
함수를 삭제합니다.
fun main() {
var favoriteActor: String = "Sandra Oh"
}
favoriteActor
변수를null
에 재할당한 다음 이 프로그램을 실행합니다.
fun main() {
var favoriteActor: String = "Sandra Oh"
favoriteActor = null
}
다음 오류 메시지가 표시됩니다.
Kotlin에서 null을 허용하는 유형과 null을 허용하지 않는 유형 간에는 차이가 있습니다.
- null을 허용하는 유형은
null
을 보유할 수 있는 변수입니다. - null을 허용하지 않는 유형은
null
을 보유할 수 없는 변수입니다.
null
을 보유하도록 명시적으로 지정하는 경우에만 null을 허용하는 유형입니다. 오류 메시지에서 알 수 있듯이 String
데이터 유형은 null을 허용하지 않는 유형이므로 변수를 null
에 재할당할 수 없습니다.
Kotlin에서 null을 허용하는 변수를 선언하려면 유형 끝에 ?
연산자를 추가해야 합니다. 예를 들어 String?
유형은 문자열이나 null
을 보유할 수 있는 반면 String
유형은 문자열만 보유할 수 있습니다. null을 허용하는 변수를 선언하려면 null을 허용하는 유형을 명시적으로 추가해야 합니다. null을 허용하는 유형이 없으면 Kotlin 컴파일러는 null을 허용하지 않는 유형이라고 추론합니다.
favoriteActor
변수 유형을String
데이터 유형에서String?
데이터 유형으로 변경합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
favoriteActor = null
}
null
재할당 전과 후에favoriteActor
변수를 출력한 다음 이 프로그램을 실행합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor)
favoriteActor = null
println(favoriteActor)
}
출력은 다음 코드 스니펫과 같습니다.
Sandra Oh null
favoriteActor
변수는 원래 문자열을 보유했으며 null
로 변환됩니다.
직접 해 보기
이제 null을 허용하는 String?
유형을 사용할 수 있습니다. Int
값으로 변수를 초기화하고 null
에 재할당할 수 있나요?
null을 허용하는 Int
값 작성
main()
함수의 모든 코드를 삭제합니다.
fun main() {
}
- null을 허용하는
Int
유형의number
변수를 만들어10
값을 할당합니다.
fun main() {
var number: Int? = 10
}
number
변수를 출력한 다음 이 프로그램을 실행합니다.
fun main() {
var number: Int? = 10
println(number)
}
예상대로 출력됩니다.
10
number
변수를null
에 재할당하여 변수가 null을 허용함을 확인합니다.
fun main() {
var number: Int? = 10
println(number)
number = null
}
- 프로그램의 마지막 줄로 다른
println(number)
문을 추가한 다음 이 프로그램을 실행합니다.
fun main() {
var number: Int? = 10
println(number)
number = null
println(number)
}
예상대로 출력됩니다.
10 null
3. null을 허용하는 변수 처리
앞에서 .
연산자를 사용하여 null을 허용하지 않는 변수의 메서드와 속성에 액세스하는 방법을 알아봤습니다. 이 섹션에서는 이 연산자를 사용하여 null을 허용하는 변수의 메서드와 속성에 액세스하는 방법을 알아봅니다.
null을 허용하지 않는 favoriteActor
변수의 속성에 액세스하려면 다음 단계를 따르세요.
main()
함수의 코드를 모두 삭제한 후String
유형의favoriteActor
변수를 선언하고 좋아하는 배우의 이름에 할당합니다.
fun main() {
var favoriteActor: String = "Sandra Oh"
}
length
속성을 사용하여favoriteActor
변수 값의 글자 수를 출력한 다음 이 프로그램을 실행합니다.
fun main() {
var favoriteActor: String = "Sandra Oh"
println(favoriteActor.length)
}
예상대로 출력됩니다.
9
favoriteActor
변수의 값에 9개의 글자(공백 포함)가 있습니다. 좋아하는 배우 이름의 글자 수는 다를 수 있습니다.
null을 허용하는 변수의 속성에 액세스
좋아하는 배우가 없는 사람이 null
에 변수를 할당할 수 있도록 favoriteActor
변수를 null을 허용하는 유형으로 만들고 싶은 경우를 가정하겠습니다.
null을 허용하는 favoriteActor
변수의 속성에 액세스하려면 다음 단계를 따르세요.
favoriteActor
변수를 null을 허용하는 유형으로 변경한 다음 이 프로그램을 실행합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor.length)
}
다음 오류 메시지가 표시됩니다.
컴파일 오류입니다. 이전 Codelab에서 언급했듯이 컴파일 오류는 코드의 문법 오류로 인해 Kotlin이 코드를 컴파일할 수 없을 때 발생합니다.
Kotlin은 null
안전성을 얻을 수 있게 의도적으로 문법 규칙을 적용합니다. 이는 잠재적 null
변수에서 실수로 호출이 발생하지 않도록 보장한다는 의미입니다. 그렇다고 해서 변수가 null
일 수 없는 것은 아닙니다. 즉, 변수의 멤버에 액세스하는 경우 변수는 null
일 수 없습니다.
이 조건이 중요한 이유는 앱 실행 중에 null
인 변수의 멤버에 액세스(null
참조라고 함)하려는 시도가 있는 경우 null
변수에 속성이나 메서드가 포함되어 있지 않으므로 앱이 비정상 종료되기 때문입니다. 이러한 유형의 장애를 런타임 오류라고 하며, 코드를 컴파일하고 실행한 후에 오류가 발생합니다.
Kotlin의 null
안전성 특성 덕분에 Kotlin 컴파일러가 null을 허용하는 유형에 관해 null
검사를 강제하므로 이러한 런타임 오류가 방지됩니다. Null
검사는 변수에 액세스하여 null을 허용하지 않는 유형으로 처리하기 전에 변수가 null
인지 확인하는 프로세스입니다. null을 허용하는 값을 null을 허용하지 않는 유형으로 사용하려면 null
검사를 명시적으로 실행해야 합니다. 자세한 내용은 이 Codelab 후반의 if/else
조건문 사용 섹션에서 알아봅니다.
이 예에서는 favoriteActor
변수의 length
속성에 관한 직접 참조가 허용되지 않으므로(변수가 null
일 가능성이 있기 때문) 컴파일 시간에 코드가 실패합니다.
이제 null을 허용하는 유형을 작업하는 다양한 기법과 연산자를 알아보겠습니다.
?.
안전 호출 연산자 사용
?.
안전 호출 연산자를 사용하여 null을 허용하는 변수의 메서드나 속성에 액세스할 수 있습니다.
?.
안전 호출 연산자를 사용하여 메서드나 속성에 액세스하려면 변수 이름 뒤에 ?
기호를 추가하고 .
표기법으로 메서드나 속성에 액세스합니다.
?.
안전 호출 연산자를 사용하면 null을 허용하는 변수에 더 안전하게 액세스할 수 있습니다. Kotlin 컴파일러가 null
참조에 관한 멤버 액세스 시도를 중지하고 액세스된 멤버의 null
을 반환하기 때문입니다.
null을 허용하는 favoriteActor
변수의 속성에 안전하게 액세스하려면 다음 단계를 따르세요.
println()
문에서.
연산자를?.
안전 호출 연산자로 대체합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor?.length)
}
- 이 프로그램을 실행한 후 예상대로 출력되는지 확인합니다.
9
좋아하는 배우 이름의 글자 수는 다를 수 있습니다.
favoriteActor
변수를null
에 재할당한 다음 이 프로그램을 실행합니다.
fun main() {
var favoriteActor: String? = null
println(favoriteActor?.length)
}
다음과 같이 출력됩니다.
null
null
변수의 length
속성에 액세스하려고 해도 프로그램이 비정상 종료되지 않습니다. 안전 호출 표현식은 단순히 null
을 반환합니다.
null이 아닌 어설션 연산자 !!
사용
또한 null이 아닌 !!
어설션 연산자를 사용하여 null을 허용하는 변수의 메서드나 속성에 액세스할 수 있습니다.
null을 허용하는 변수 뒤에 null이 아닌 !!
어설션 연산자를 추가하고 그 뒤에 .
연산자, 메서드나 속성을 차례로 공백 없이 추가해야 합니다.
null이 아닌 !!
어설션은 이름에서 알 수 있듯이 변수의 값이 null
이 아님(실제 여부에 관계없이)을 어설션합니다.
?.
안전 호출 연산자와 달리 null이 아닌 !!
어설션 연산자를 사용하면 null을 허용하는 변수가 실제로 null
일 때 NullPointerException
오류가 발생할 수 있습니다. 따라서, 변수가 항상 null 비허용 변수이거나 적절한 예외 처리가 설정된 경우에만 실행해야 합니다. 적절히 처리되지 않으면 예외로 인해 런타임 오류가 발생합니다. 예외 처리에 관해서는 이 과정의 후반 단원에서 알아봅니다.
null이 아닌 !!
어설션 연산자를 사용하여 favoriteActor
변수의 속성에 액세스하려면 다음 단계를 따르세요.
- 좋아하는 배우의 이름에
favoriteActor
변수를 재할당한 후println()
문에서?.
안전 호출 연산자를 null이 아닌!!
어설션 연산자로 대체합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor!!.length)
}
- 이 프로그램을 실행한 후 예상대로 출력되는지 확인합니다.
9
좋아하는 배우 이름의 글자 수는 다를 수 있습니다.
favoriteActor
변수를null
에 재할당한 다음 이 프로그램을 실행합니다.
fun main() {
var favoriteActor: String? = null
println(favoriteActor!!.length)
}
NullPointerException
오류가 발생합니다.
이 Kotlin 오류는 실행 중에 프로그램이 비정상 종료되었음을 나타냅니다. 따라서 변수가 null
이 아님이 확실하지 않다면 null이 아닌 !!
어설션 연산자를 사용하지 않는 것이 좋습니다.
if/else
조건문 사용
if/else
조건문에서 if
브랜치를 사용하여 null
검사를 실행할 수 있습니다.
null
검사를 실행하려면 !=
비교 연산자를 사용하여 null을 허용하는 변수가 null
과 같지 않은지 확인하면 됩니다.
if/else
문
다음과 같이 if/else
문을 null
검사와 함께 사용할 수 있습니다.
null 검사는 if/else
문과 함께 사용할 때 유용합니다.
nullableVariable != null
표현식의null
검사는if
조건으로 사용됩니다.if
브랜치 내의 본문 1은 변수가 null을 허용하지 않는다고 가정합니다. 따라서 이 본문에서는?.
안전 호출 연산자나 null이 아닌!!
어설션 연산자를 사용하지 않는 null 비허용 변수인 것처럼 변수의 메서드나 속성에 자유롭게 액세스할 수 있습니다.else
브랜치 내의 본문 2는 변수가null
이라고 가정합니다. 따라서 이 본문에서는 변수가null
일 때 실행해야 하는 문을 추가할 수 있습니다.else
브랜치는 선택사항입니다.if
조건문을 사용하여null
검사에 실패하는 경우에만 기본 작업을 제공하지 않고null
검사를 실행할 수 있습니다.
null
검사는 코드에 null을 허용하는 변수를 사용하는 줄이 여러 개 있을 때 if
조건과 함께 사용하기에 더 편리합니다. 이와 달리 ?.
안전 호출 연산자는 null을 허용하는 변수의 단일 참조에 더 편리하게 사용할 수 있습니다.
favoriteActor
변수에 관한 null
검사로 if/else
문을 작성하려면 다음 단계를 따르세요.
- 좋아하는 배우의 이름에
favoriteActor
변수를 재할당한 후println()
문을 삭제합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
}
favoriteActor != null
조건이 있는if
브랜치를 추가합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
}
}
if
브랜치 본문에"The number of characters in your favorite actor's name is ${favoriteActor.length}"
문자열을 허용하는println
문을 추가한 다음 이 프로그램을 실행합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
}
}
예상대로 출력됩니다.
The number of characters in your favorite actor's name is 9.
좋아하는 배우 이름의 글자 수는 다를 수 있습니다.
null
검사 후 if
브랜치 내의 length
메서드에 액세스하므로 .
연산자로 이름의 길이 메서드에 직접 액세스할 수 있습니다. 따라서 Kotlin 컴파일러는 favoriteActor
변수가 null
일 가능성이 없다는 것을 알고 있으므로 컴파일러는 속성에 관한 직접적인 액세스를 허용합니다.
- 선택사항: 배우의 이름이
null
인 상황을 처리하려면else
브랜치를 추가합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
}
}
else
브랜치 본문에"You didn't input a name."
문자열을 사용하는println
문을 추가합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
favoriteActor
변수를null
에 할당한 다음 이 프로그램을 실행합니다.
fun main() {
var favoriteActor: String? = null
if(favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
예상대로 출력됩니다.
You didn't input a name.
if/else
표현식
null
검사를 if/else
표현식과 결합하여 null을 허용하는 변수를 null을 허용하지 않는 변수로 변환할 수도 있습니다.
null을 허용하지 않는 유형에 if/else
표현식을 할당하는 방법은 다음과 같습니다.
nullableVariable != null
null
검사는if
조건으로 사용됩니다.if
브랜치 내의 본문 1은 변수가 null을 허용하지 않는다고 가정합니다. 따라서 이 본문에서는?.
안전 연산자나 null이 아닌!!
어설션 연산자가 없는 null 비허용 변수인 것처럼 변수의 메서드나 속성에 액세스할 수 있습니다.else
브랜치 내의 본문 2는 변수가null
이라고 가정합니다. 따라서 이 본문에서는 변수가null
일 때 실행해야 하는 문을 추가할 수 있습니다.- 본문 1과 2의 마지막 줄에서
null
검사에 통과하거나 실패할 때 null을 허용하지 않는 변수에 할당되도록 null을 허용하지 않는 유형을 야기하는 표현식이나 값을 각각 사용해야 합니다.
if/else
표현식을 사용하여 단일 println
문만 사용하도록 프로그램을 다시 작성하려면 다음 단계를 따르세요.
- 좋아하는 배우의 이름에
favoriteActor
변수를 할당합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
lengthOfName
변수를 만들어if/else
표현식에 할당합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if(favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
if
브랜치와else
브랜치에서 모두println()
문을 삭제합니다.
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if(favoriteActor != null) {
} else {
}
}
if
브랜치 본문에favoriteActor.length
표현식을 추가합니다.
fun main() {
val favoriteActor: String? = "Sandra Oh"
val lengthOfName = if(favoriteActor != null) {
favoriteActor.length
} else {
}
}
favoriteActor
변수의 length
속성에는 .
연산자를 사용하여 직접 액세스합니다.
else
브랜치 본문에0
값을 추가합니다.
fun main() {
val favoriteActor: String? = "Sandra Oh"
val lengthOfName = if(favoriteActor != null) {
favoriteActor.length
} else {
0
}
}
이름이 null
인 경우 0
값이 기본값 역할을 합니다.
main()
함수 끝에"The number of characters in your favorite actor's name is $lengthOfName."
문자열을 사용하는println
문을 추가한 다음 이 프로그램을 실행합니다.
fun main() {
val favoriteActor: String? = "Sandra Oh"
val lengthOfName = if(favoriteActor != null) {
favoriteActor.length
} else {
0
}
println("The number of characters in your favorite actor's name is $lengthOfName.")
}
예상대로 출력됩니다.
The number of characters in your favorite actor's name is 9.
사용한 이름의 문자 수는 다를 수 있습니다.
?:
Elvis 연산자 사용
?:
Elvis 연산자는 ?.
안전 호출 연산자와 함께 사용할 수 있는 연산자입니다. ?:
Elvis 연산자를 사용하면 ?.
안전 호출 연산자가 null
을 반환할 때 기본값을 추가할 수 있습니다. if/else
표현식과 비슷하지만 더 직관적인 방식으로 표현됩니다.
변수가 null
이 아닌 경우에는 ?:
Elvis 연산자 앞의 표현식이 실행됩니다. 변수가 null
이면 ?:
Elvis 연산자 뒤의 표현식이 실행됩니다.
?:
Elvis 연산자를 사용하도록 이전 프로그램을 수정하려면 다음 단계를 따르세요.
if/else
조건문을 삭제한 후lengthOfName
변수를 null을 허용하는favoriteActor
변수로 설정하고?.
안전 호출 연산자를 사용하여length
속성을 호출합니다.
fun main() {
val favoriteActor: String? = "Sandra Oh"
val lengthOfName = favoriteActor?.length
println("The number of characters in your favorite actor's name is $lengthOfName.")
}
length
속성 뒤에?:
Elvis 연산자와0
값을 추가한 다음 이 프로그램을 실행합니다.
fun main() {
val favoriteActor: String? = "Sandra Oh"
val lengthOfName = favoriteActor?.length ?: 0
println("The number of characters in your favorite actor's name is $lengthOfName.")
}
앞의 출력과 동일하게 출력됩니다.
The number of characters in your favorite actor's name is 9.
4. 결론
축하합니다. null 허용 여부에 관해 알아보고 다양한 연산자를 사용하여 관리하는 방법을 알아봤습니다.
요약
- 변수를
null
로 설정하여 변수에 값이 없음을 나타낼 수 있습니다. - null을 허용하지 않는 변수에는
null
을 할당할 수 없습니다. - null을 허용하는 변수에는
null
을 할당할 수 있습니다. - null을 허용하는 변수의 메서드나 속성에 액세스하려면
?.
안전 호출 연산자나 null이 아닌!!
어설션 연산자를 사용해야 합니다. if/else
문을null
검사와 함께 사용하여 null을 허용하지 않는 컨텍스트에서 null을 허용하는 변수에 액세스할 수 있습니다.if/else
표현식을 사용하여 null을 허용하는 변수를 null을 허용하지 않는 유형으로 변환할 수 있습니다.- null을 허용하는 변수가
null
인 경우if/else
표현식 또는?:
Elvis 연산자로 기본값을 제공할 수 있습니다.