728x90
반응형
엘비스 연산자(?:)
- 코틀린은 엘비스 연산자(?:)를 사용하여 디폴트 값을 편하게 지정할 수 있다.
fun foo(s: String?) = s ?: ""
fun strLenSafe(s: String?): Int = s?.length ?: 0
- return이나 throw등의 연산도 식이니, 엘비스 연산자의 우항에 넣을 수도 있다.
fun printlnShippingLabel(person: Person){
val address = person.company?.address
?: throw IllegalArgumentException("No address")
with(address){
println(streetAddress)
println("$zipCode $city, $country")
}
}
안전한 캐스트: as?
- 자바와 마찬가지로 코틀린에서도 as로 지정한 타입으로 바꿀 수 없다면
ClassCaseException
이 발생한다. - as를 사용할 때마다 is를 통해 변환 가능한 타입인지 검사할 수 있지만, 귀찮다.
- as?연산자는 대상 타입으로 변환할 수 없으면 Exception발생 대신 null을 반환한다.
class Person(val firstName: String, val lastName: String){
override fun equals(o: Any?): Boolean{
// 타입이 일치하지 않으면 false
val otherPerson = o as? Person ?: return false
return otherPerson.firstName == firstName &&
otherPerson.lastName == lastName
}
...
}
널이 아님을 단언: !!
- 널 아님 단언(not-null assertion)을 사용하면 어떤 값이든 강제로 널이 될 수 없는 타입으로 바꿀 수 있다. (느낌표 이중)
- 실제 널에 대해 !!를 적용하면 NPE가 발생한다.
fun ignoreNulls(s: String?){
val sNotNull = s!!
println(sNotNull.length)
}
ignoreNulls(null)
// kotlin.KotlinNullPointerException
- !!를 사용하여 예외가 발생했을 경우, 스택트레이스가 !!를 선언한 파일의 줄수로 나오니 한줄에 !!단언문을 쓰는 일은 피해야 한다.
person.company!!.address!!.country // x
let 함수
- let 함수는 널이 될 수 있는 식을 더 쉽게 다를 수 있게 해준다.
- let 함수는 자신의 수신 객체를 인자로 전달받은 람다에게 넘긴다.
- 널이 될 수 있는 값에 대해 안전한 호출 구문을 사용해 let을 호출하되 널이 될 수 없는 타입을 받는 람다를 let에 전달한다.
fun sendEmailTo(email: String){
println("send to $email")
}
// let 미사용
val person: Person? = getTheBestPersonInTheWorld()
if(person != null) {
sendEmailTo(person.email)
}
// let 사용
getTheBestPersonInTheWorld()?.let { sendEmailTo(it) }
나중에 초기화할 프로퍼티 지정하기
- 코틀린에서는 클래스 안에 널이 될 수 없는 프로퍼티를 생성자 안에서 초기화하지 않으면 다른 메서드에서 초기화가 불가능하다.
- 초기화 값을 제공할 수 없으면, 널이 될 수 있는 타입을 사용해야한다.
- 하지만 이렇게 되면 해당 프로퍼티를 접근할때 마다 널검사를 해야하는 번거로움이 있다.
- junit 예제 클래스를 살펴보자.
class MyService {
fun performAction(): String = "foo"
}
class MyTest{
// null로 초기화 하기 위해 널이 될 수 있는 타입 선언
private var myService: MyService? = null
// setUp 메소드 안에서 초깃값을 지정
@Before
fun setUp(){
myService = MyService()
}
// 널 가능성에 신경을 써야함
@Test fun testAction(){
Assert.assertEqauls("foo", myService!!.performAction())
}
}
- 코틀린은 이런 문제를 해결하기 위해
lateinit
변경자를 지원한다. - lateinit 변경자를 붙이면 프로퍼티를 나중에 초기화 할 수 잇다.
class MyService {
fun performAction(): String = "foo"
}
class MyTest{
// 초기화하지 않고 널이 될 수 없는 프로퍼티 선언
private lateinit var myService: MyService = null
// setUp 메소드 안에서 초깃값을 지정
@Before
fun setUp(){
myService = MyService()
}
// null을 신경쓸 필요가 없음
@Test fun testAction(){
Assert.assertEqauls("foo", myService.performAction())
}
}
lateinit
프로퍼티는 항상var
여야 한다.
타입 파라미터의 널 가능성
- 코틀린에서는 함수/클래스의 모든 타입 파라미터는 기본적으로 널이 될 수 있다.
- 타입 파라미터 T는 최상위 클래스인 Any?의 하위 클래스이므로, 물음표가 없더라도 T는 널이될 수 있는 타입이다.
- 따라서 널이 불가능한 타입일 때는 상한(upper bound)를 지정하여, null이 아님을 확실하게 한다.
fun<T> printHashCode(t: T){
// t가 null이 될 수 있으므로, 안전한 호출을 써야한다.
println(t?.hashCode())
}
fun<T: Any> printHashCode2(t: T){
// 상한(upper bound)를 지정하면, null이 아님을 확실히한다.
println(t.hashCode())
}
fun main(){
printHashCode(null)
printHashCode2(null) // 컴파일 에러
printHashCode2(42)
}
728x90
반응형
'프로그래밍 노트 > Kotlin' 카테고리의 다른 글
[Kotlin] 산술/비교 연산자 오버로딩 (0) | 2023.06.29 |
---|---|
[Kotlin] 코틀린 데이터 타입 (0) | 2023.03.27 |
[Kotlin] 널이 될 수 있는 타입, 안전한 호출 연산자(?.) (0) | 2020.12.15 |
[Kotlin] 수신 객체 지정 람다: with와 apply (0) | 2020.12.14 |
[Kotlin] 코틀린 지연 계산(lazy) 컬렉션 연산 (0) | 2020.12.13 |