🌱
Kotlin-in-Action 1 ~ 4장
March 24, 2023
중복되는 내용이지만 Kotlin in Action 1,2,3,4장 정리를 모아놓았습니다.
Kotlin
1장
- 코틀린의 빌더 패턴이란, 디자인 패턴 빌더 패턴과 같다. (p.44)
JuiceBuilder()
.water(100)
.ice(20)
.orange(5)
.banana(10)
.build()
이처럼 Builder를 만들어 사용하는데, 파라미터가 명시적이고 필수 파라미터를 확인할 수 있다. 외에도 여러 이점이 있어 Lombok에서도 지원하는 패턴인데 코틀린의 경우,
Juice(
water = 100,
ice = 20,
oranger = 5,
banana = 10
)
생성자에 변수 명을 명시할 수 있고, 매개변수별로 기본값을 가질 수 있다. 때문에 이 자체로 빌더 패턴이 구현되어 있어 이를 용이하게 사용하면 좋다.
- 1장은 코틀린의 주요 특성인 다양한 플랫폼, 정적 타입 언어, 함수형 + 객체 지향, 무료 오픈소스 대해 말한다.
- 코틀린의 철학
- 실용성
- 간결성
- 안전성
- 상호운용성
2장
- 대입문은 자바에서 식, 코틀린에서는 문이다.
- 코틀린에서는
a = b = c
와 같이 사용할 수 없다.
- 코틀린에서는
- 모든 변수를 val 선언, 변경이 불가피할때만 var 이용하자.
- 자바의 문자열 접합 연산은 내부적으로
StringBuilder
를 사용해 효율적이다.- 코틀린의 문자열 템플릿 또한 마찬가지로 효율적.
- 프로퍼티를 기본으로 지원하여, Class의 필드에 대해 게터 세터가 생성된다.
- 변수 타입은 is로 검사하고, 이후엔 스마트 캐스트를 통해 캐스팅하지 않아도 검사된 타입으로 취급한다.
if (sth is Int) { val newSth = sth as Int } // 불필요
// 캐스팅하지 않아도 if 안에선 sth은 Int로 스마트 캐스팅 되어있다.
- Exception 또한 식이다. 자바와 사용은 같으나 throws 절이 없다.
- 자바는 checked Exception 에 대해 명시적 처리를 하지만 코틀린은 checked, unchecked를 구분하지 않는다.
3장 함수 정의와 호출
- 프로퍼티도 최상위 수준에 놓을 수 있다. (함수도)
package blog
val aString: String
var aInt: Int = 0
const val THE_INT = 1
fun test() = println("HI test")
- const를 붙이면 pubilc static final 이 된다.
fun String.lastChar(): Char
처럼 확장할 클래스의 이름(수신 객체 타입)을 명시하고 확장 함수를 정의할 수 있다.- 확장함수가 캡슐화를 깨지는 않는다. 내부적으로 수신 객체를 첫 번째 인자로 받는 정적 메서드이다.
- 당연히 확장 함수 내부에서 private, protected 멤버는 접근이 불가하다.
- 확장 함수는 단지 정적 메서드 호출에 대한 문법적인 편의(syntatic sugar)
- Java
...
== Kotlinvararg
(가변 길이 인자)*aList
는 배열을 명시적으로 풀어준다.
- 중위 호출은
infix
변경자를 함수 앞에 붙여주어 구현한다.- ex)
infix fun Any.to(other: Any) = Pair(this, other)
- ex)
4장 클래스, 객체, 인터페이스
- interface는 구현된 메서드를 가진다.(default method 처럼)
- default 구현이 둘 이상의 인터페이스가 가지면, override 필수
- Kotlin의 class, method는 기본이 final
- 상속을 허용하려면
open
(override
메서드는 open이다.) - 이로 인해 스마트 캐스트가 가능하다는 이점이 생긴다.
- 프로퍼티가 val + 커스텀 접근자 x 일 때만 스마트 캐스트
- 상속 후 프로퍼티의 커스텀 접근자를 정의하면 스마트 캐스트 요구 사항이 깨질 수 있다.
- 상속을 허용하려면
package-private
은 없고, 모듈 내부에서만 접근 가능한internal
internal open class TalkativeButton: Focusable {
private fun yell() = println("HEY!")
protected fun whisper() = println("whisper")
}
fun TalkativeButton.giveSpeech() { // ERROR: internal class이므로 노출할 수 없다.
yell() // ERROR: private method
whisper() // ERROR: protected method 같은 패키지에서 접근이 불가하다.
}
- kotlin nested class는 변경자가 없으면 java 내부 static class와 같다.
- 바깥 클래스에 대한 참조를 포함하게 하려면
inner
변경자를 사용한다.
- 바깥 클래스에 대한 참조를 포함하게 하려면
sealed
클래스 상속을 제한한다.- 하위 클래스는 모두 상위 클래스의 nested class 로 존재해야한다.
when
에서 else문이 강제되지 않아, 예외로 인한 버그를 예방한다.
sealed
접근자의 제한과 코틀린 1.5에서 개선된 점을 알아보쟈 sealed 접근자
- 주 생성자, 부 생성자, 초기화 블록 등이 있다.
- DI 프레임워크 등에서 parameter 없는 생성자가 필요한 경우가 있는데, 코틀린은 default 값을 통해 해결한다. (안전성과 가독성에 괜찮은걸까?)
- 인터페이스는 프로퍼티를 가질 수 있고, 이는 하위 클래스가 확장 시 구현해야한다.
- 프로퍼티는 값을 저장하는 프로퍼티, 커스텀 접근자에서 매번 계산하는 프로퍼티 두 가지가 있다.
- 쉽게 말해 게터를 정의한 경우와, 값이 대입된 프로퍼티 두 가지이다.
- setter에서
field
로 필드 값을 가져올 수 있다. private get
,private set
으로 접근자의 가시성 변경 가능하다.
- setter에서
- 쉽게 말해 게터를 정의한 경우와, 값이 대입된 프로퍼티 두 가지이다.
by
키워드로 위임을 할 수 있다.- 코틀린은 상속에서 발생하는 문제를 위해 기본이
final
이다.
상속 불가인 클래스에 대해 데코레이터 패턴을 이용해 하위 타입처럼 생성할 수 있다.- 데코레이터 패턴의 구현의 복잡성을 지원해주는 것이 바로
by
- 코틀린은 상속에서 발생하는 문제를 위해 기본이
class DelegatingCollection<T>: Collection<T> {
private val innerList = arrayListOf<T>()
override val size: Int = innerList.size
override fun isEmpty(): Boolean = innerList.isEmpty()
...
}
class DelegatingCollection<T>(
innerList: Collection<T> = ArrayList<T>()
) : Collection<T> by innerList {}
- 위의 과정이 아래와 같이 단순해진다.
- object 선언은 싱글턴 패턴을 지원한다.
- 코틀린은
static
이 없지만,패키지 수준의 최상위 함수 + object
가 있다. Companion Object
내부에 private 생성자, 정적 멤버를 생성하기 좋다Companion Object
는 바깥 클래스의 private 멤버에 접근이 가능하기 때문이다.- 여기에 팩토리 패턴을 구현하자.
- 자바에서 사용하기 위해 static으로 만들고 싶다면
@JvmStatic