1장 코틀린 설치와 실행
apply plugin: 'kotlin-android'
- 안드로이드용 코틀린 플러그인 적용
apply plugin: 'kotlin-android-extensions'
- 안드로이드 코틀린 익스텐션 적용
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
- 코틀린 표준 라이브러리 의존성.
- JDK7 혹은 JDK8 용 확장 함수 사용 및 바이트코드 생성 가능
kotlin-reflect
- 리플렉션을 위함
kotlin-test / kotlin-test-junit
- 코틀린 테스트를 위함
2장 코틀린 기초
https://mg-laboratory.tistory.com/256
- 단언 (!!) 연산자가 하나라도 있다는 이는 Code Smell 이다. 가능하면 사용하지 않도록 노력하자
- val middleNameLength = p.middle?.length ?: 0
@JvmOverloads
- 코틀린에서는 모든 인자를 전달하지 않더라도 오버로딩이 동작하지만, 이를 Java 에서호출하기 위해서는 어노테이션 추가가 필요하다.
@JvmOverlads
fun addProduct(name: String, price: Double = 0.0, desc: String? = null)
- Java 의 super 가 호출되는 것이 아니라 각각의 생성자가 모두 추가된다
3장 코틀린 객체 지향 프로그래밍
- 컴파일 타임 상수(const val)는 반드시 object 나 companion object 선언의 최상위 속성 또는 멤버여야 한다
- 문자열 또는 기본 타입의 래퍼 클래스이며 getter 를 가질 수 없다
Backing Field
- 프로퍼티에 대한 접근을 감시하고, 제어하는 숨겨진 필드
- getter/setter 가 속성값에 직접 접근하지 않고, Backing Field를 통해 값을 저장하고 처리
by lazy
: 처음 접근 시 초기화
: val 속성에 사용
late init
- not-null 변수에만 사용 가능
- 기본 타입은 사용 불가
- var 속성에 적용
singleton
- class 대신 object 사용
- java 에서는 MySingleton.INSTANCE 로 접근가능
Nothing 클래스
- 생성 불가
- 결코 존재할 수 없는 값(클래스?)을 나타내기 위해 사용
- Object 같은 느낌인데, 생성불가한 클래스?
4장 함수형 프로그래밍
trailrec fun
- 꼬리 재귀호출 시, stack 프레임을 재사용하게해준다
- 컴파일 시 while 을 사용한 반복문으로 리팩토링됨
- 마지막 연산에서 자기 자신을 호출해야함
- try-catch-finally 블록 안에서 사용 불가
5장 컬렉션
배열
- val strings = arrayOf("apple", "banana")
- val nullStringArray = arrayOfNulls<String>(5)
- val squares = Arrays(5) { i -> (i * i).toString() }
- for ((index, value) in array.withIndex())
변경 불가능한 컬렉션
- listOf
- SetOf
- mapOf
변경 가능한 컬렉션
- mutableListOf
- mutableSetOf
- mutableMapOf
컬렉션 to map
val keys = 'a' .. 'f'
val map = keys.associate { it to it.toString().repeat(5).capitalize() }
{ a = Aaaaa, b = Bbbbb, ...}
범위 값 제한
val range = 3..8
5.coerceIn(range)
5.coerceIn(3, 8)
- 범위에 속하는 경우 해당 값을 리턴하고, 그렇지 않은 경우 경계 값 리턴
같은 크기로나누기
val range = 0..10
val chunked = range.chunked(3)
chunked { it.sum() }
- 실제로 windowed 함수로 구현되어 있다
- windowed(elementSize, step, partialWindows = true)
: elementSize - 각 윈도우에 포함될 원소의 개수
: step - 각 단계마다 전진할 원소의 개수
리스트 구조 분해하기
val (a, b, c, d, e) = listOf("a", "b", "c", "d", "e", "f")
정렬하기
data class Golfer(val score: Int, val first: String, val last: String)
golfers.sortedWith(compareBy( { it.score }, { it.last }, { it.first } )
컬렉션에서 특정 타입 원소들만 필터링하기
val strings = list.filterIsInstance<String>()
val strings = list.filterIsInstanceTo(mutableListOf<String>())
6장 시퀀스
- 컬렉션과 다르게 lazy 처리된다
- 자바 스트림과는 다르게 코틀린의 일부 시퀀스는 여러 번 순회할 수 있다
Short Circuit
- 특정 조건에 다다를 때까지 오직 필요한 데이터만을 처리하는 방식
시퀀스 생성하기
- val sequence1 = sequenceOf(1, 2, 3, 4)
- val sequence2 = listOf(1, 2, 3, 4).asSequence()
- generateSequence(seed) {nextFunction}
- takeWhile() : 특정 조건에 대해서 동작한다
7장 영역 함수
- apply() : 객체 생성 시, 생성자 외에 초기화 동작이 필요할 때 사용 가능
- also() : 코드 흐름을 방해하지 않고 부수적인 동작이 필요할 때 사용 가능
- let() : null 이 아닌 레퍼런스에 대해 코드를 수행하고 null 인 경우에는 기본 값 리턴 가능
: 연산 결과를 임시 변수에 할당하지 않고 처리하고 싶을 때
8장 코틀린 대리자
- 대리자를 사용해서 합성 구현하기
class SmartPhone (
private val phone: Dialable = Phone(),
private val camera: Snappable = Camera()
) : Dialable by phone, Snappable by camera
- by 키워드는 포함된 객체에 있는 모든public 함수를 이 객체를 담고 있는 컨테이너를 통해 노출할수 있다
lazy 대리자 사용하기
- 사용되는 시점에 초기화 수행
- val test: Int by lazy (mode: LazyThreadSafetyMode) { initializer }
- SYNCHRONIZED : 오직 하나의 스레드만 Lazy 인스턴스를 초기화할 수 있게 락을 사용
- PUBLICATION : 초기화 함수가 여러 번 호출될 수 있지만 첫 번째 리턴값만 사용
- NONE : Lock 이 사용되지 않음
notNull 대리자 사용하기
- var shouldNotBeNull: String by Delegates.notNull<String>()
- 속성 초기화 전에 접근하는 경우에 Exception 을 발생시킴
observable 대리자
- var watched: Int by Delegates.observable(1) { prop, old, new -> }
- 값이 변경될 때 동작을 수행할 수 있다
vetoable 대리자
- var checked: Int by Delegates.vetoable(0) { prop, old, new -> new >= 0 }
- 값이 변경되기 전에 조건을 확인하여 값의 변경을 방지할 수 있다
Map 대리자
data class Project (val map: MutableMap<String, Any?>) {
val name: String by map
val priority: Int by map
var completed: Boolean by map
}
- map 에 k,v 가 3쌍이 있고, 각각의 value 값이 property 로 대입된다.
- Project(mutableMapOf("name" to "Kotlin", "priority" to 5, "completed" to true))
9장 테스트
테스트 클래스 수명주기 설정하기
- Junit5 에서 @TestInstance(TestInstance.Lifecycle.PER_CLASS) 설정
- 위와 같이 설정하면 companion object 에 @BeforeClass 추가없이 테스트 객체를 한번만 생성하도록 사용할 수 있음
- 아래와 같은 방법으로 각 테스트 클래스에 매번 선언할 필요 없이 설정가능하다
- src/test/resource/junit-platform.properties 파일에
junit.jupiter.testinstance.lifecycle.default = per_class
데이터 클래스 테스트
- Junit5 의 assertAll() 을 사용하면 data 클래스의 여러 property 의 값을 한번에 검증할 수 있다
- 1번째 assertion 이 실패하더라도 나머지 assertion 을 모두 수행한다
- 이보다 assertion 하나를 이용해 2개 객체 간의 값을 비교할 수 있다
val book = service.findBookById("1555")
val expected = Book(isbn = "1555", title = "hello")
assertThat(book, is(expected))
10장 입력/출력
use 로 리소스 관리하기
- try-with-resources 가 지원되지 않기에 use() 혹은 File.useLines() 를 이용한다
11장 그 밖의 코틀린 기능
반복적으로 람다 실행하기
- repeat(5) { 코드 }
완벽한 when 강제하기
- when() {}.exhaustive
- else 구문을 작성하도록 강제한다
실행 가능한 클래스 만들기
- 아래 메소드 1개를 가진 클래스를 정의하면 실행가능하다
operator fun invoke()
- val request = AstroRequest()
val result = request()
경과 시간 측정하기
- var time = measureTimeMillis {}
쓰레드 사용하기
- thread {}
TODO 로 완성 강제하기
- TODO() 함수가 호출되면 Error 를 발생시킨다
함수 이름에 특수 문자 사용하기
- 백틱( `) 을 사용하면 공백을 추가할 수 있다
- 테스트에서만 사용한다
- 코드에서는 밑줄을 사용하는 것이 낫다
12장 스프링 프레임워크
- skip
13장 코루틴과 구조적 동시성
코루틴 빌더 선택하기
- runBlocking 빌더
: 명령줄 검증 또는 테스트에 유용
: 모든 내부 코루틴이 종료될때까지 현재 스레드를 블록
: runBlocking {}
- launch 빌더
: coroutineScope 의 확장 함수이다
: 독립된 프로세스를 실행하는 코루틴을 시작하고, 해당 코루틴에서 리턴값을 받을 필요가 없을 때 사용
- async 빌더
: coroutineScope 의 확장 함수이다
: 값을 리턴해야 하는 경우에 사용한다
: await() 를 통해 동작 완료를 기다린다
: delay() 는 쓰레드를 중단하지 않고 코루틴을 대기 상태로 만드는 일시 중단 함수
- coroutineScope 빌더
: 종료 전에 포함된 모든 코루틴이 완료될 때까지 기다리는 일시 중단 함수다
: runBlocking 과 다르게 Main Thread 를 블록하지 않는다
async/await 를 withContext 로 변경하기
- async(Dispatcher.IO) {}.await()
- withContext(Dispatcher.IO) {}
디스패처 사용하기
- launch, async, withContext 의 인자로 추가하면 된다
- Dispatchers.Default : 공유 백그라운드 스레드 풀을 사용한다
- Dispatchers.IO : 파일 I/O 또는 블록킹 네트워크 I/O 같은 작업을 위해 설계된 on-demand 공유 풀을 사용한다
- Dispatchers.Unconfined : 일반 어플리케이션 코드에서는 사용해서는 안 된다.
- Dispatchers.Main : 안드로이드에서 UI 작업을 위해 사용한다 (안드로이드에서 추가로 제공)
: kotlinx-coroutines-android 의존성을 추가해야 한다
자바 스레드 풀에서 코루틴 실행하기
- val dispatcher = Executors.newFixedThreadPool(10).asCoroutineDispatcher().use { }
코루틴 취소하기
- val job = launch {}
job.cancel() //동작을 취소한다
job.join() // job 이 완료될때까지 기다렸다가 프로그램을 종료한다
- withTimeout(1000L) {}
- withTimeoutOrNull(1000L) {}
'SW > SW 서적' 카테고리의 다른 글
///Modern Java in Action / 한빛미디어 (0) | 2025.02.18 |
---|---|
///Kotlin in Action / 드미트리 제메로프, 스베트라나 이사코바 / 에이콘출판 (0) | 2024.07.21 |
///SQL Anti Patterns / 빌 카윈 / 인사이트 (0) | 2024.04.01 |
///C# 프로그래밍 입문 / 강상진, 장현태 / 한빛미디어 (0) | 2022.12.31 |
조엘 온 소프트웨어 / 조엘 스포스키 / 에이콘출판 (0) | 2022.07.04 |