티스토리 뷰
코틀린과 자바의 대표적인 차이점이 몇 가지 있는데 그중 Null Safety에 대해서 기록.
Java와 같은 여러 언어들은 기본적으로 객체에 Null 값을 허용해 줍니다.
그렇기 때문에 Null 객체를 호출해서 사용을 하려고 하고, 이때 null 참조 예외 ( == NullPointerException == NPE )가 발생합니다.
정말,, 많이 본 오류 ^^,,
그래서 코틀린은 객체가 기본적으로 Null을 허용하지 않도록 해서 NPE 오류를 없애려고 합니다.
하지만 기본 값이 Non-Null이지 Nullable로 객체를 선언할 수 있습니다.
Non-Null, Nullable 객체 선언
var a: String = "abc" // 기본적으로 a 변수를 선언하고 값을 할당하는 경우 Null이 아님을 의미
a = null // a 변수에 null을 할당하면 컴파일 오류가 발생
null을 허용하려면 아래처럼 ?
를 이용해서 변수를 nullable 문자열로 선언할 수 있습니다.
var b: String? = "abc" // 자료형 뒤에 ?를 사용하면 Nullable 변수
b = null // 정상
print(b)
결국 코틀린에서도 Nullable로 객체를 생성하면 NPE 오류가 발생할 수 있는데 이걸 방지하기 위해 코틀린에서는 여러 방법을 제공합니다.
Safe calls ( = 안전한 호출 ) ?.
아래 코드는 String 형의 Nullable 객체이며, null로 b 변수를 초기화시켰습니다.
null이기 때문에 b.length를 출력할 경우 오류가 발생해야 하지만, ?. 연산자를 사용해서 null 값이 출력됩니다.
val b: String? = null
println(b?.length) // null
이 연산자는 chain 형태로 연속적인 변수의 null을 체크할 때 유용합니다.
아래처럼 작성하면 if문을 중복으로 사용해서 조건별로 null을 출력하지 않고 한 줄로만 null을 반환하거나, 값을 출력하거나가 가능합니다.
bob?.department?.head?.name
위처럼 체인 형태로 작업을 하면 bob, department, head, name과 같은 프로퍼티 중 하나라도 null이라면 null을 return 하게 됩니다.
null이 아닐 경우만 특정 작업을 실행하려면 let 연산자를 함께 사용할 수 있습니다.
val listWithNulls: List<String?> = listOf("Kotlin", null)
for (item in listWithNulls) {
item?.let { println(it) } // prints Kotlin and ignores null
}
Null을 허용하는 String 리스트를 listWithNulls의 이름으로 선언하고 Kotlin과 null이라는 값으로 초기화해주었습니다.
그 후 for문으로 listWithNulls를 순차 출력 하는데 ?.let을 사용하면 null이 아닌 경우에만 { } 사이의 명령어를 수행하기 때문에 Kotlin 만 출력되고 null은 출력되지 않습니다.
값을 할당할 때도 Safe call을 사용할 수 있습니다.
person?.department?.head = managersPool.getManager()
person이나 department 중 하나라도 null 값이라면 managersPool.getManager() 함수를 호출하지 않습니다.
Elvis 연산자 ?:
만약 Nullable 한 변수 b를 사용할 경우 b가 null이 아니면 b값을 사용하고, null이라면 다른 명령을 하고 싶을 때 아래와 같이 코드를 작성할 수 있을 것입니다.
val l: Int = if (b != null) b.length else -1
?: 를 사용하면 한 줄로 코드를 바꿀 수 있습니다.
val l = b?.length ?: -1
뿐만 아니라 return과 throw 작업도 처리가 가능합니다.
fun foo(node: Node): String? {
val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ...
}
null이 아님을 보증하는 연산자 !!
nullable 한 변수에!! 를 사용하면 개발자가 이 변수는 null이 아니라고 보증하게 됩니다.
NPE 상황이 발생하므로 완전하게 보증할 수 있는 상황이 아니면 사용하지 말고, NPE 예외 처리가 필요할 경우만 사용하는 게 좋습니다.
실제로 개발할 때 사용 해본 적은 없음.
var a: String? = null
val len = a!!.length
안전한 캐스팅 as?
다른 자료형으로 변경을 하는 경우 오류가 발생하면 ClassCastException이 발생하는데 이걸 as? 연산자를 이용해서 보완할 수 있습니다.
val a: String = "test"
val b: Int? = a as? Int
a 변수에 test라는 문자열을 넣고 b 변수에 a 변수를 Int 형으로 변환해서 넣는데 String은 Int 형으로 형변환이 불가능하므로 ClassCastException이 발생하는 게 맞지만, b 변수를 ? 를 이용해서 Nullable 하게 선언하고 as? 연산자를 사용하면 b 변수에 null이 할당됩니다.
Nullable 유형의 Collection
nullable 유형의 컬렉션이 있고 null이 아닌 요소를 필터링하려는 경우 filterNotNull을 사용해서 null값을 거를 수 있습니다.
val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()
이렇게 다양하게 null을 처리할 수 있는 방법을 알아봤습니다.
'JAVA, Kotlin' 카테고리의 다른 글
[Kotlin] 예외 처리 (0) | 2023.04.09 |
---|---|
@Resource, @Autowired, @Inject 차이 (0) | 2021.11.01 |
람다 Lambda 란? (0) | 2021.06.23 |
컴파일러 vs 인터프리터 (0) | 2021.03.04 |
== 와 equals 차이? (0) | 2021.03.03 |