Chapter 6. 코틀린 타입 시스템

6.1 널 가능성

6.1.1 널이 될 수 있는 타입

타입 이름 뒤에 물음표(?) -> null 참조를 저장할 수 있다는 뜻



6.1.2 타입의 의미

타입: 어떤 값들이 가능한지와 그 타입에 대해 수행할 수 있는 연산의 종류를 결정



6.1.3 안전한 호출 연산자: ?.

?. : null 검사와 메소드 호출을 한 번의 연산으로 수행

s?.toUpperCase() // if (s != null) s.toUpperCase() else null 과 같음



6.1.4 엘비스 연산자: ?:

엘비스 연산자(?:) : null 대신 사용할 디폴트 값을 지정할 때 사용하는 연산자

fun foo(s: String?) {
	val t: String = s ?: "" // "s"가 null이면 결과는 빈 문자열
}
// 엘비스 연산자를 활용해 널 값 다루기
fun strLenSafe(s: String?) : Int = s?.length ?: 0
println(strLenSafe("abc")) // 3
println(strLenSafe(null)) // 0



6.1.5 안전한 캐스트: as?

as?: - 어떤 값을 지정한 타입으로 캐스트하는데, 값을 대상 타입으로 변환할 수 없으면 null을 반환



6.1.6 널 아님 단언: !!

!! : null이면 NullPointerException 발생, 어떤 값이든 널이 될 수 없는 타입으로 강제로 바꿈



6.1.7 let 함수

foo?.let { ...it... }
1) foo != null => it은 람다 안에서 널이 아니다.
2) foo == null => 아무 일도 일어나지 않는다.

// let을 사용해 null이 아닌 인자로 함수 호출하기
fun sendEmailTo(email: String) {
	println("Sending email to $email")
}

var email: String? = "[email protected]"
email?.let { sendEmailTo(it) } // Sending email to [email protected]

email = null
email?.let { sendEmailTo(it) } // 아무일도 x



6.1.8 나중에 초기화할 프로퍼티

lateinit 변경자 : 프로퍼티를 나중에 초기화할 수 있음, 해당 프로퍼티는 항상 var이어야 함.



6.1.9 널이 될 수 있는 타입 확장



6.1.10 타입 파라미터의 널 가능성



6.1.11 널 가능성과 자바

@Nullable + Type = Type?
@NotNull + Type = Type

[플랫폼 타입]
: 널 관련 정보를 알 수 없는 타입 => 널이 될 수 있는 타입으로 처리해도 되고, 널이 될 수 없는 타입으로 처리해도 됨

  • 자바 타입은 코틀린에서 플랫폼 타입으로 표현됨

[상속]
코틀린에서 자바 메소드를 오버라이드할 때 그 메소드의 파라미터와 반환 타입을 널이 될 수 있는 타입으로 선언할지 널이 될 수 없는 타입으로 선언할지 결정해야 함




6.2 코틀린의 원시 타입

6.2.1 원시 타입: Int, Boolean 등

코틀린은 원시 타입과 래퍼 타입을 구분하지 않음



6.2.2 널이 될 수 있는 타입: Int?, Boolean? 등



6.2.3 숫자 변환

코틀린은 한 타입의 숫자를 다른 타입의 숫자로 자동 변환하지 x

val i = 1
val l: Long = i // 컴파일 오류 발생

val i = 1
val l: Long = i.toLong() // 변환 함수 사용

=> 명시적 변환이 필요

  • 숫자 리터럴 사용할 때는 변환 함수 필요 x
  • 산술 연산자를 사용할 때도 변환 필요 x
fun foo(l: Long) = println(l)
val b: Byle = l
val l = b + 1L
foo(42) // 42



6.2.4 Any, Any?: 최상위 타입

Any 타입 : 모든 널이 될 수 없는 타입의 조상 타입(원시 타입을 포함한 모든 타입의 조상 타입)

  • Object에 있는 다른 메소드를 호출하고 싶다면 Any에서 Object타입으로 값을 캐스트 해야 함.



6.2.5 Unit 타입: 코틀린의 void

Unit 타입: 자바 void와 같은 기능

  • void와 다른 점 - 모든 기능을 갖는 일반적인 타입 -> 타입 인자로 쓸 수 있음



6.2.6 Nothing 타입: 이 함수는 결코 정상적으로 끝나지 않는다

Nothing 타입 - 아무 값도 포함하지 않음

fun fail(message: String) : Nothing {
	throw IllegalStateException(message)
}

val address = company.address ?: fail("No address")
println(address.city)




6.3 컬렉션과 배열

6.3.1 널 가능성과 컬렉션

List<Int?> : 리스트 안의 각 값이 널이 될 수 있음
List<Int>? : 전체 리스트가 널이 될 수 있음

컬렉션.filterNotNull() : 널이 될 수 있는 값으로 이뤄진 컬렉션에서 널 값을 걸러내는 함수



6.3.2 읽기 전용과 변경 가능한 컬렉션

Collection : 읽기 전용 컬렉션
MutableCollection : 변경 가능한 컬렉션



6.3.3 코틀린 컬렉션과 자바

[컬렉션 생성 함수]

컬렉션 타입 읽기 전용 타입 변경 가능 타입
List listOf mutableListOf, arrayListOf
Set setOf mutableSetOf, hashSetOf, linkedSetOf, sortedSetOf
Map mapOf mutableMapOf, hashMapOf, linkedMapOf, sortedMapOf



6.3.4 컬렉션을 플랫폼 타입으로 다루기

  • 컬렉션이 널이 될 수 있는가?
  • 컬렉션의 원소가 널이 될 수 있는가?
  • 오버라이드하는 메소드가 컬렉션을 변경할 수 있는가?



6.3.5 객체의 배열과 원시 타입의 배열

코틀린에서 배열을 만드는 방법

  • arrayOf 함수에 원소를 넘기기
  • arrayOfNulls 함수에 정수 값을 인자로 넘기면 모든 원소가 null이고 인자로 넘긴 값과 크기가 같은 배열 만듦
  • Array 생성자는 배열 크기와 람다를 인자로 받아서 람다를 호출해서 각 배열 원소를 초기화
val letters = Array<String>(26) { i -> ('a' + i ).toString() }
println(letters.joinToString(""))

toTypedArray() : 컬렉션을 배열로 바꿔줌

[원시 타입의 배열을 만드는 방법]

  • 각 배열 타입의 생성자는 size 인자를 받아서 해당 원시 타입의 디폴트 값으로 초기화 된 size 크기의 배열 반환
  • 팩토리 함수 (예: intArrayOf 등)는 여러 값을 가변 인자로 받아서 그런 값이 들어간 배열을 반환
  • 크기와 람다를 인자로 받는 생성자를 사용

좋은 웹페이지 즐겨찾기