아래의 글은 드미트리 제메로프, 스베트라나 이사코바 저/오현석역,『Kotlin in Action』,에이콘출판사(2017)의 내용을 기반으로 작성하였습니다.
안전한 호출 : ?.
엘비스연산자 : ?:
널아님단언 : !!
수신객체전달 : let 함수
다른타입변환 : as?
널 가능 타입 : nullable type
읽기 전용 컬렉션 :
fun strLen(s: String) = s.length // s는 널이 될수 없음.
fun strLen(s: String?) = ... // s는 널이 될 수 있음.
en.wikipedia.org/wiki/Data_type
Data type - Wikipedia
This article is about types of data. For more general types, including those of functions and modules, see type (computer science). Python 3: the standard type hierarchy In computer science and computer programming, a data type or simply type is an attribu
en.wikipedia.org
A data type constrains the values that an expression, such as a variable or a function, might take. This data type defines the operations that can be done on the data, the meaning of the data, and the way values of that type can be stored.
데이터 타입은 컴파일러나 인터프리터가 프로그래머에게 데이터를 어떻게 다루워야하는지를 알려주는 부가 정보를 포함한다. 데이터 타입은 수행할 수 있느 변수나 함수의 제약을 표현한다. 데이터 타입은 데이터에 수행할 수있는 명령과 데이터의 의미와 저장하는 방식에 대해서 정의한다.
fun printAllCaps(s: String?) {
val allCaps: String? = s?.toUpperCase()
printin(allCaps)
}
class Employee(val name: String val manager: String?)
fun managerName(employee: Employee) : String? = employee.manager?.name
class Address(val streeAddress: String, val zipCode: Int,
val city: String, val country: String)
class Company(val name: Stirng, val address: Address?)
class Person(val name: String, val company: Company?)
fun Person.countyName(): String {
val country = this.company?.address?.country
return if (countrey != null) country else "Unknown"
}
엘비스 연산자 : ?: : null coalescing
코들린에서는 return이나 throw 등의 연산도 식이다.
엘비스 연산자의 우향에 return throw 등의 연산을 넣을 수 있음
fun foo(s: String?) {
val t: String = s ?: ""
}
s ?: ""
if s != null
return s
else
""
fun strLenSafe(s: String?): Int = s?.length ?: 0
fun Person.countryName() = company?.address?.country ?: "Unknown"
안전한 캐스트 : as?
class Person(val firstName: String, val lastName: String) {
override fun equals(o: Any?): Boolean {
val otherPerson = o as? Person ?: return false
return otherPerson.firstName == firstName &&
otherPerson.lastName == lastName
}
override fun hashCode(): Int =
firstName.hashCode() * 37 + lastName.hashCode()
}
널아님 체크 : !!
fun ignoreNulls(s: String?) {
val sNotNull: String = s!!
println(sNotnull.length)
}
let 함수
자신의 수신 객체를 인자로 전달받은 람다에게 넘긴다
let 함수도 널이 될 수 있는 타입의 값에 대해 호출할 수 있지만 let은 this가 널인지 검사하지 않는다.
fun sendEmailTo(email: String) {...}
if (email != null) sendEmailTo(email)
fun sendEmailTo(email: String) {
println("Sending email to $email")
}
var email: String? = "yole@example.com"
email?.let { sendEmailTo(it) }
email = null
email?.let { sendEmailTo(it) }
// 2줄
val person: Person? = getTheBestPersonInTheWorld()
if (person != null) sendEmailTo(person.email)
// 한줄로 줄일 수 있음
getTheBestPersonInTheWorld()?.let { sendEmailTo(it.email) }
나중에 초기화할 프로퍼티
코틀린에서 클래스 안의 널이 될 수 없는 프로퍼티는 생성자 안에서 초기화 해야함
lateinit 키워드는 나중에 초기화 가능, 나중에 초기화 하는 프로퍼티는 var로 해야함. val은 final이므로 생성자 안에서 초기화 해야함.
널이 될 수 있는 타입 확장
널이 될수 있는 확장 함수를 정의하면 null 값을 다루는 좋은 도구로 활용
코틀린에서는 널이 될 수 있는 타입의 확장 함수 안에는 this가 널이 될 수 있다는 점이 자바와 다르다
let 함수도 널이 될 수 있는 타입의 값에 대해 호출할 수 있지만 let은 this가 널인지 검사하지 않는다.
fun verifyUserInput(input: String) {
if (input.isNullOrBlank()) {
println("Please fill in the required fields")
}
}
fun String?.isNullOrBlank(): Boolean = this == null || this.isBlank()
val person: Person ? = ...
person.let { sendEmailTo(it) }
>> ERROR
person?.let { sendEmailTo(it) }
타입 파라미터 널 가능성
널 가능성과 자바
@Nullable + Type = Type?
@NotNull + Type = Type
널 인식 가능한 annotation package :
javax.annotation
android.support.annotation
org.jetbrains.annotation
이런 널 가능성 annotation 이 소스코드에 없는 경우 = 코틀린 플랫폼 타입
플랫폼 타입
코틀린이 널 관련 정보를 알수 없는 타입 : 그 타입은 널이 될 수 있는 타입으로 처리해도 되고 널이 될 수 없는 타입으로 처리해도 된다.
결국 알수 없으므로 에러 발생의 책임을 구현자에게 위임
코틀린 컴파일러는 public 함수의 널이 아닌 타입인 파라미터와 receiver에 대한 널 검사를 자동 추가
왜 플랫폼 타입을 도입했는가?
즉 > 모든 자바 타입을 널이 될 수 있는 타입으로 다루면 더 안전하지 않을까? 즉 널 체크를 하면 되지 않을까?
그럼 null이 아닌 값에도 null 체크를 하게 된다.
ArrayList<String?> 이면 이 값의 원소에 접근할 때마다 널 검사 수행 - > 안정성보다 검사 비용이 더 많이 호출됨 - > 비효율적
자바코드에서 가져온 타입만 플랫폼 타입이 됨
String! 타입은 자바에서 자바 코드에서 온 타입
상속에 대해서도 널 가능성
자바 클래스나 인터페이스를 코틀린에서 구현할 경우 널 가능성을 제대로 처리하는 일이 중요
구현 메소드를 다른 코틀린 코드가 호출가능하므로 코틀린 컴파일러는 널이 될 수 없는 타입에 선언한 모든 파라미터에 널 아님을 체크하는 단언문을 만들어줌
// java
interface StringProcessor {
void process(String value)
}
// kotlin
class StringPrinter: StringProcessor {
override fun process(value: String) {
println(value)
}
}
class NullableStringPrinter: StringProcessor {
override fun process(value: String?) {
if (value != null)
println(value)
}
}
'독서관련 > Kotlin in Action' 카테고리의 다른 글
CH06 코틀린 컬렉션 및 배열 (0) | 2021.01.17 |
---|---|
CH06 코틀린 primative 타입 (0) | 2021.01.11 |
CH05 코틀린 람다 함수형 인터페이스 (0) | 2021.01.06 |
CH05 코틀린 람다 컬렉션 API (0) | 2021.01.05 |
CH05 코틀린 람다 (0) | 2021.01.05 |