23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
from: https://kotlinlang.org/docs/null-safety.html#safe-casts
kotlin은 기본적으로 변수에 null을 할당할 수 없도록 제약하고 있다.
kotlin에서 NullPointerException (NEP) 가 발생할 수 있는 원인은 다음과 같다.
명시적으로 throw NullPointerException() 을 수행한경우
'!!' 오퍼레이터를 사용한경우
다음과 같은 경우 초기화와 관련된 데이터 불일치가 발생한다.
생성자에서 사용할 수 있는 초기화 되지 않은 this가 전달되어 사용된경우
수퍼클래스 생성자가 오픈 멤버를 호출한경우, 이때 오픈멤버가 초기화 되지 않은 객체인경우
자바와 함께 사용하는 경우
참조하는 Java 대상 객체가 널인경우
자바 코드가 Generic 타입을 담는 객체에 널은 대입하고 이를 kotlin이 참조하는 경우
다음 코드와 같이 변수에 null을 대입하는 경우 컴파일 오류가 난다.
// 일반적으로 변수에는 널을 할당할 수 없다.
var a: String = "abc"
a = null // compilation error 가 발생한다. 다음과 같이 <타입>? 으로 지정한경우 널을 할당할 수 있다.
// 다음 변수에는 널을 설정할 수 있다.
var b: String? = "abc"
b = null // 널을 할당할 수 있다.
print(b)샘플을 활용하면 다음과 같다.
fun main(args: Array<String>) {
var a: String = "Hello1"
var b: String? = "World"
b = null
print(b)
// 다음은 NEP가 발생하지 않고 안전한 코드가 된다.
// 즉 val은 한번 값을 할당하면 다시 할당이 불가능하기 때문이다.
val l = a.length
// 다음은 널이 될 수없어서 오류가 난다.
// 01.NullTest.kt:13:13: error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
val l2 = b.length
}다음과 같이 b가 널인지 명시적으로 확인하고 두 옵션을 별도로 처리할 수 있다.
val l = if (b != null) b.length else -1다음은 널체크를 수행하는 방법을 보여준다.
val b: String? = "Kotlin"
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}중요한 것중에서 val로 값을 할당하면 널에 대해서 안전하게 처리할 수 있다. (즉, 한번할당하면 값을 재 할당할 수 없으므로 널에 안전하게 처리할 수 있다.)
'?.' 을 이용하면 값이 널이라도 안전하게 처리할 수 있다.
이 의미는 널이 아니면 해당 값에 대한 참조를 수행하고, 널인경우라면 결과로 널을 반환한다.
val a = "Kotlin"
val b: String? = null
println(b?.length)
println(a?.length) // Unnecessary safe call즉 위 코드는 b가 널인경우 null을 반환한다.
결과는 다음과 같다.
null
6다음과 같이 '?.' 은 체인으로 호출이 가능하다.
bob?.department?.head?.name다음과 같이 리스트에 대해서 널에 대해서 안전하게 작업을 수행할 수 있다.
val listWithNulls: List<String?> = listOf("Kotlin", null)
for (item in listWithNulls) {
item?.let { println(it) } // prints Kotlin and ignores null
}결과는 다음과 같다.
Kotlin확장 함수는 nullable 수신가에서 정의될 수 있다.
이렇게 하면 각 호출 사이트에서 null 검사 논리를 사용할 필요 없이 null에 대한 동작을 수행할 수 있다.
toString() 함수는 nullable receiver로 구현되어 있다.
널이 전달되면 이는 "null" 을 출력한다.
val person: Person? = null
logger.debug(person.toString()) // Logs "null", does not throw an exception위와 같이 person.toString() 인경우 person이 널이라도 NEP가 일어나지 않는다.
안전하게 호출한다면 다음과 같이 호출하자.
var timestamp: Instant? = null
val isoTimestamp = timestamp?.toString() // Returns a String? object which is `null`
if (isoTimestamp == null) {
// Handle the case where timestamp was `null`
}널이 아닌경우 정상 처리를 수행하고, 널인경우 대안 처리를 하고자 한다면 엘비스 연산자를 사용하자.
val l: Int = if (b != null) b.length else -1위 내용을 엘비스 연산자로 구현하면 다음과 같다.
val l = b?.length ?: -1대안 작업에 예외도 던질 수 있다.
fun foo(node: Node): String? {
val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ...
}위와 같이 node.getName()가 널인경우 IllegalArgumentException 이 발생한다.
'!!' 은 널이아닌지 검사하고, 널이 아닌경우 원래 값을 반환하고, 널인경우 NEP를 발생시킨다.
val l = b!!.length만약 NEP를 원한다면 위와 같이 명시적으로 예외를 던질 수 있다.
값을 다른값으로 타입 캐스팅을 할때 값이 널이면 ClassCastException이 발생한다.
특정 타입에서 다른 타입으로 안전하게 캐스팅 하기 위해서는 다음과 같이 안전한 타입 캐스팅을 할 수 있다.
val aInt: Int? = a as? Int위와 같이 a 값을 안전하게 Int 로 캐스팅이 가능하다.
val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()위와 같이 리스트의 값중에 널이 있는경우 filterNotNull() 함수를 이용하면 널이 아닌 값만 추출할 수 있다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.