관리 메뉴

피터의 개발이야기

[Kotlin] 널 안정성, Null safety 본문

Programming/Kotlin

[Kotlin] 널 안정성, Null safety

기록하는 백앤드개발자 2024. 5. 15. 10:10
반응형

 

ㅁ 들어가며

이 글은 코틀린 공식문서를 공부하며 번역한 글입니다.

 

 

ㅁ Null Safety란?

코틀린의 타입(type) 시스템은 Billion Dollar Mistake라고도 알려진 null 참조 코드의 위험성을 없애기 위한 것입니다.

 

  Java를 포함한 많은 프로그래밍 언어에서 가장 일반적인 함정 중 하나는, null 참조의 멤버에 접근하면 null 참조 예외(null reference exception)가 발생한다는 것입니다. Java에서는 이것을 NullPointerException 또는 NPE라고 합니다.

 

 Kotlin에서 NPE가 발생하지 않도록 방지하기 위해 Nullable, Non-Nullable 타입을 구분하고 있습니다.

 

ㅁ Kotlin NullPointerException 발생 원인

  • throw NullPointerException을 명시적으로 호출하는 것
  • 아래에서 설명하는 것과 같이 !! 연산자를 사용하는 것
  • 초기화와 관련하여 아래와 같은 특성으로 데이터의 불일치가 발생할 때:
  • Java interoperation:
    • 플랫폼 유형 null 참조에서 멤어에 접근하려고 시도함
    • Java 상호 운용에 사용되는 일반 유형의 Null 허용 문제입니다.  
      • e.g)Java code의 일부가 Kotlin MutableList에 추가되면서 Nullable 형태 그대로인 MutableList<String?>로 적용됩니다.
    • 외부의 자바 코드로 인한 기타 문제들

 

ㅁ Nullable, Non-Nullable

 Nullable, Non-Nullable 두 가지 유형이 있다. Nullable은 null인 값을 표현할 수 있고, Non-Nullable은 null이 아닌 값만 표현할 수 있다.

var a: String = "abc"
a = null // 컴파일 에러 발생

ㅇ 컴파일 시 null이면 에러가 발생합니다.

 

// Kotlin null 표현
var number : Int? = null
var str: String? = "Hello, world"

 ㅇ null을 참조하기 위해서는 String?과 같이 선언해야 합니다.

 

ㅁ Nullable 속성 및 함수 

fun main() {
    var a: String? = "ABC"
    var b: String? = "ABC"
    var c: String? = "ABC"
    var d: String? = "ABC"

    // null이 아닌지를 확인하는 if 문장 속에서 Non-nullable로 취급 (스마트 캐스트)
    if (a != null) { println(a.length) }
    
    // ?. b가 null이 아니면 결과를 리턴하고 b가 null인 경우 null을 반환하는 안전콜
    println(b?.length)

    // !!를 이용하면 강제적으로 사용할 수 있다 (실행시 에러가 발생할 수 있으므로 위험)  
    println(c!!.length)
    
    // 엘비스 연산자 (?:)를 사용하여 null는 되지 않도록 한다.
    d = d ?: "(Unknown)"
    println(d.length)
    
    // 안전한 케스팅, 객체가 대상 유형이 아닌 경우 오류가 발생할 수 있다. 이런 경우 Null인지 체크하여 캐스트를 사용한다.
    val aInt: Int? = a as? Int
    // java
    Integer aInt = (a instanceof Integer) ? (Integer) a : null;
}

ㅇ 참조: devkuma - nullable

 

# let, also, run은 scope function이다.

이들 함수는 [Kotlin] Scope Functions (let, with, run, apply, also) 정리에서도 정리하였다.

ㅁ let() 메서드

ㅇ 참조가 nullable이 아닌 값을 보유하는 경우에만 작업을 실행하려면 let 연산자를 사용할 수 있다.

val firstName = "Tom"
val secondName = "Michael"
val names: List<String?> = listOf(firstName, null, secondName)

ㅇ names list에 null을 포함시켰다.

 

var res = listOf<String?>()
for (item in names) {
    item?.let { res = res.plus(it) }
}

assertEquals(2, res.size)
assertTrue { res.contains(firstName) }
assertTrue { res.contains(secondName) }

ㅇ let 함수를 사용하여 이름목록의 null이 아닌 모든 요소에 대해 작업을 실행할 수 있다.

 

ㅁ also() 메서드

var res = listOf<String?>()
for (item in names) {
    item?.let { res = res.plus(it); it }
  ?.also{it -> println("non nullable value: $it")}
}

ㅇ 예를 들어 null이 아닌 모든 값에 대한 로깅과 같은 몇 가지 추가 작업을 적용하려면 also () 메서드를 사용하고 이를 let()과 연결할 수 있다.

 

non nullable value: Tom
non nullable value: Michael

ㅇ null이 아닌 모든 요소를 ​​출력한다.

 

ㅁ run() 메서드

var res = listOf<String?>()
for (item in names) {
    item?.run{res = res.plus(this)}
}

ㅇ Kotlin에는 null 허용 참조에 대해 일부 작업을 실행하는 run()가 있습니다 . 이는 let()과 매우 유사 하지만 함수 본문 내에서 Run() 메서드는 함수 매개 변수 대신  this를 참조하여 작동한다.

 

ㅁ 함께 보면 좋은 사이트

Kotlin의 Null 안전에 대한 종합 가이드

kotlin doc- Null safety

devkuma - Kotlin 변수 선언

반응형
Comments