6.1.3 안전한 호출 연산자
1. 호출하려는 값이 null이 아니면 일반 메서드 호출처럼 작동
2. 호출하려는 값이 null이라면 호출이 무시되고 null이 결과 값
fun main(args: Array<String>) {
printAllCaps("abc")
printAllCaps(null)
}
fun printAllCaps(s: String?) {
val allCaps: String? = s?.uppercase()
println(allCaps)
}
2. ?. 연산자를 사용하여 안전한 호출 연쇄
class Address(val streetAddress: String, val city: String, val country: String)
class Company(val name: String, val address: Address?)
class Person(val name: String, val company: Company?)
fun Person.countryName(): String {
val country = this.company?.address?.country
return if (country != null) country else "UnKnown"
}
fun main(args: Array<String>) {
val person = Person("Alice", null)
println(person.countryName())
}
6.1.4 엘비스 연산자: ?:
1. null 대신 사용할 디폴트 값을 지정할 때 사용 가능
2. 좌항 값이 null이 아니면 좌항 값을 결과 값으로 하고, null이면 우항 값을 결과 값으로 함
fun main(args: Array<String>) {
println(foo("Hello"))
println(foo(null))
}
fun foo(s: String?): String {
return s ?: "nulling"
}
class Address(val streetAddress: String, val city: String, val country: String)
class Company(val name: String, val address: Address?)
class Person(val name: String, val company: Company?)
fun Person.countryName() = company?.address?.country ?: "Unknown"
fun main(args: Array<String>) {
val person = Person("Alice", null)
println(person.countryName())
}
3. 엘비스 연산자의 우항에 return, throw 등의 연산을 넣을 수 있음
fun Person.countryName() = company?.address?.country ?: "Unknown"
fun printShippingLabel(person: Person) {
val address = person.company?.address ?: throw IllegalArgumentException("No address")
with(address) {
println(streetAddress)
println("$zipCode $city, $country")
}
}
fun main(args: Array<String>) {
val address = Address("Elsestr. 47", 80687, "Munich", "Germany")
val jetbrains = Company("JetBrains", address)
val person = Person("Alice", jetbrains)
val person2 = Person("Bob", null)
printShippingLabel(person)
printShippingLabel(person2)
}
6.1.5 안전한 캐스트: as?
1. 어떤 값을 지정한 타입으로 변환할 수 없으면 null을 반환
class Person(val firstName: String, val lastName: String) {
override fun equals(other: Any?): Boolean {
val otherPerson = other as? Person ?: return false
return otherPerson.firstName == firstName &&
otherPerson.lastName == lastName
}
}
fun main(args: Array<String>) {
val person = Person("Dmitry","Jemerov")
val person2 = Person("Dmitry","Jemerov")
println(person == person2)
println(person.equals(42))
}
6.1.6 널 아님 단언: !!
1. 느낌표를 이중으로 사용하여 어떤 값이든 null이 될 수 없는 타입으로 강제 변환
fun ignoreNulls(s: String?) {
val sNotNull: String = s!!
println(sNotNull.length)
}
fun main(args: Array<String>) {
ignoreNulls(null)
}
2. 단, !!를 null에 대해 사용해서 발생하는 예외의 스택 트레이스에는 어떤 파일의 몇 번째 줄인지에 대한 정보는
들어있지만, 어떤 식에서 예외가 발생했는지에 대한 정보가 들어있지 않음
- 어떤 값이 null이었는지 확실히 하기 위해 여러 !! 단언문을 한 줄에 쓰는 것을 피할 것
person.company!!.address!!.country
6.1.7 let 함수
fun sendEmailTo(email: String) {
/* ... */
}
if (email != null) sendEmailTo(email)
-> sendEmailTo 함수는 null이 될 수 없는 타입의 값을 파라미터로 받기 때문에 인자를 넘겨주기 전에,
주어진 값이 null 값인지 검사해야함
-> let 함수를 통해 인자를 전달할 수 있음
1. 안전한 호출 연산자와 함께 사용하면 원하는 식을 평가해서 결과가 null인지 검사한 후,
그 결과를 변수에 넣는 작업을 간단히 수행할 수 있음
2. null이 될 수 있는 값에 대해 안전한 호출 구문을 사용해 let을 호출하되,
null이 될 수 없는 타입을 인자로 받는 람다를 let에 전달
fun main(args: Array<String>) {
val email: String? = "test@naver.com"
email?.let {
email -> sendEmailTo(email)
}
}
3. it을 사용하여 인자 전달이 가능
fun sendEmailTo(email: String) { // 널이 될 수 없는 파라미터
println("sending email to $email")
}
fun main(args: Array<String>) {
val email: String? = "test@naver.com"
email?.let { sendEmailTo(it) }
val email2: String? = null
email2?.let { sendEmailTo(it) } // 아무 일도 일어나지 않음
}
4. 여러 값이 null인지 검사 -> let 호출을 중첩시켜 사용
- But. let을 중첩시켜 처리하면 코드가 복잡해져 알아보기 어려우므로, 일반적인 if를 사용해 모든 값을 한꺼번에
검사하 는 것이 나음
6.1.8 나중에 초기화할 프로퍼티
1. lateinit 변경자를 통해 프로퍼티를 나중에 초기화 할 수 있음
- 나중에 초기화할 프로퍼티는 항상 var이어야 함
class MyService {
fun performAction(): String = "foo"
}
class MyTest {
// 초기화하지 않고 null이 될 수 없는 프로퍼티 선언
private lateinit var myService: MyService
@Before
fun setUp() {
myService = MyService()
}
@Test
fun testAction() {
Assert.assertEqauls("foo", myService.performAction())
}
}
6.1.10 타입 파라미터의 널 가능성
1. 함수나 클래스의 코든 타입 파라미터는 기본적으로 null이 될 수 있음
- 타입 파라미터 T를 클래스나 함수 안에서 타입 이름으로 사용하면 이름 끝에 물음표가 없더라도
T가 null이 될 수 있는 타입
fun <T> printHashCode(t: T) {
println(t?.hashCode())
}
fun main(args: Array<String>) {
printHashCode(null)
}
2. 타입 파라미터가 null이 아님을 확실히 하기 위해서는 null이 될 수 없는 타입 상한을 지정해야함
'Android > Kotlin' 카테고리의 다른 글
[코틀린 인 액션] 8장 정리: 고차 함수 (0) | 2022.12.13 |
---|---|
[코틀린 인 액션] 7장 정리: 연산자 오버로딩 (0) | 2022.12.05 |
[코틀린 인 액션] 5장 정리 (0) | 2022.11.30 |
[코틀린 인 액션] 4장 정리 (0) | 2022.11.29 |
[코틀린 인 액션] 3장 정리 (0) | 2022.11.28 |