코틀린 컴파일 & 자바 컴파일 -> class 파일로 jar -> 코틀린 런타임에서 실행
if
/when
/throw
is expression, not statement (try
can be expression)
오버로딩 같은 상황에서 확장 함수가 클래스 내부 함수보다 우선순위가 낮다.
sealed
class
by
키워드로 클래스 위임 (decorator 패턴 구현의 대안)
팩토리 패턴 by private constructor & companion object
sequence
for lazy calculation in collection
플랫폼 타입: 코틀린이 null 관련 정보를 알 수 없는 (자바에서 가져온) 타입. 알아서 판단해야 함. (ex. String!
)
원시/래퍼 타입 구분 X, 하지만 nullable 타입이라면 자바의 래퍼 타입으로 컴파일됨. (자바에선 원시 타입이 null일 수가 없어서)
Any 타입은 자바의 Object 에 해당함.
Array 클래스는 자바 배열(array)로 컴파일 됨
(여기부터 파트 2)
위임 프로퍼티
지연 로딩: by lazy
키워드를 쓸 수 있는데, 이는 정확히 말하자면 by
키워드와 위임 객체를 반환하는 표준 라이브러리 'lazy'의 결합이다.
일반 함수 호출의 경우엔 JVM이 필요할 경우 알아서 함수를 inline한다.
reified
: inline 함수는 type erasure를 피할 수 있다. 이를 reify라고 한다. 이게 되는 이유: 컴파일러가 inline 함수 본문을 bytecode로 컴파일 해 호출되는 각 지점에 모두 삽입해버림. 따라서 구체적인 클래스(type)을 정확하게 알 수 있음.
모든 클래스가 무공변인 자바와 달리, 코틀린은 공변성을 띠는 경우가 있다.
out T
: T는 공변적이다. 이 T는 리턴타입에 쓰일 수 있다, 즉 값을 produce한다. (Producer<out T>)in T
: T는 반공변적이다. 이 T는 파라미터 위치에서만 쓰인다. (Consumer<in T>)(P) -> R
은 사실 Function1<P, R>
이다. 선언 지점 변성
, 메소드 레벨에서 지정하면 사용 지점 변성
이다. 후자처럼 하면 모든 지점에 명시해야 된다. (ex. ? extends X, ? super Y)리플렉션: "실행 시점에 코틀린 객체의 내부를 관찰하기"
DSL: 구조화된 API 구축에 유리
fun buildStr(action: StringBuilder.() -> Unit): String {
val sb = StringBuilder()
sb += "asd"
sb.action()
sb.toString()
}
buildStr { this.append("!") } // "asd!"
@DslMaker
로 여러 단계 바깥의 this에 접근 못하게 통제 가능fun table(init: TABLE.() -> Unit) = TABLE().apply(init)
class DependencyHandler {
fun compile(coordinate: String){
TODO()
}
operator fun invoke(body: DependencyHandler.() -> Unit){
body()
}
}
// compile 사용
dependencies.compile("junit")
// invoke (and compile) 사용
dependencies {
compile("junit")
}
suspend: CPS (continuation passing style) 변환과 state machine을 활용해 코드를 생성해내고, 이를 통해 함수에 들어가고 나가는 부분을 여러 순간으로 나눌 수 있다. (코루틴은 추가로 알아볼 예정)
좋은 책 같긴 한데, 뭔가 읽은 분량에 비해 새로 배운건 많지 않은 것 같다. 조금 더 어려운 책을 찾는게 나을 것 같다.