Kotlin은 Android 개발의 주요 언어입니다. Google Android Docs (2025)에 따르면, Android 신규 프로젝트의 95% 이상이 Kotlin을 사용합니다. Kotlin 특성을 이해하는 것 — data class, sealed class, 코루틴 및 scope functions — 은 Android 개발자에게 필수 요구 사항입니다.
주요 내용
Kotlin은 Java의 클래스 개념을 확장합니다. data class, sealed class, object 및 companion object — Java에 없거나 다르게 구현된 구조입니다.
data class — equals(), hashCode(), toString(), copy() 및 componentN()을 자동 생성하는 클래스. 데이터 모델(DTO, Entity)에 이상적. 요구 사항: 기본 생성자에 최소 하나의 매개변수, val/var, open/sealed/inner 불가. sealed class — 제한된 서브클래스 계층을 가진 클래스. 모든 서브클래스는 컴파일 시점에 알려지고 같은 파일에 선언됩니다. sealed class의 when 표현식은 else 브랜치가 필요 없습니다. sealed interface(Kotlin 1.9+) — sealed class와 동일하지만 다중 상속을 허용합니다. object — 싱글톤, object 키워드(class 아님)로 선언. 스레드 안전 지연 초기화. companion object — 클래스의 정적 멤버. 이름을 가짐(기본값 Companion). 인터페이스를 구현하고 extension functions를 가질 수 있음.
| 타입 | 설명 | 용도 |
|---|---|---|
| data class | equals, hashCode, toString, copy 자동 생성 | 데이터 모델, DTO, Entity |
| sealed class | 제한된 계층, when 검사 | 상태, 결과, UI State |
| sealed interface | sealed class + 다중 상속 | 이벤트, 액션(Kotlin 1.9+) |
| object | 싱글톤(선언적) | Factory, Utility, 상수 |
| companion object | 클래스의 정적 멤버 | Factory Method, 정적 상수 |
| enum class | 상수가 있는 열거형 | 고정 집합이 있는 상태 |
data class — 90%의 모델용. sealed class — UI State 및 결과용. object — 싱글톤용. IT Sectr는 모든 화면 상태(Loading, Success, Error)에 sealed class를 권장합니다.
Sealed class — 상태 모델링을 위한 강력한 도구. 예: UiState<T>와 서브클래스 Loading, Success(data: T), Error(message: String). when 표현식은 모든 상태 처리를 보장합니다. Sealed interface — 다중 구현이 필요한 이벤트 및 액션용. Value class(Kotlin 1.5+) — 오버헤드 없이 단일 값을 감싸는 래퍼. 타입 안전 식별자에 사용: @JvmInline value class UserId(val id: String).
Extension Function — 상속 없이 기존 클래스에 메서드 추가. fun String.isEmail(): Boolean. Extension Property — 속성에도 동일(backing field 없음). Inline Function — 함수 본문을 호출 지점에 삽입 — 호출 오버헤드 없음. 람다가 있는 higher-order 함수에 사용. Higher-Order Function — 다른 함수를 받거나 반환하는 함수. Scope Functions — 객체 컨텍스트로 작업하는 다섯 가지 함수: let, run, with, apply, also.
let — 컨텍스트 it, 람다 결과 반환. null-safe 호출에 사용(?.let {}). apply — 컨텍스트 this, 컨텍스트 반환. 객체 구성용. run — 컨텍스트 this, 람다 결과 반환. 컨텍스트를 사용한 계산용. also — 컨텍스트 it, 컨텍스트 반환. 부작용(로깅)용. with — extension 아님, 컨텍스트 this, 람다 결과 반환. 객체에 대한 작업 그룹용. Lambda — 익명 함수. Destructuring Declaration — data class를 변수로 분해: val (name, age) = person.
Inline function와 reified — JVM에서 제네릭 타입을 보존하는 유일한 방법. 용도: 타입 안전 빌더(Gson.fromJson<T>()), 타입 검사(is T), 클래스 가져오기(T::class). Crossinline 및 Noinline — inline 함수에서 람다 매개변수용 수정자. crossinline — non-local return 금지, noinline — 특정 람다의 인라인화 금지. IT Sectr는 타입으로 작업할 때만 inline + reified를 권장합니다. 일반 higher-order 함수의 경우 inline은 바이트코드 크기를 증가시킬 수 있습니다.
코루틴 — 비동기 프로그래밍을 위한 경량 스레드. 스레드를 차단하지 않고 일시 중단(suspend)됩니다. suspend function — 스레드를 차단하지 않고 일시 중단될 수 있는 함수. 코루틴이나 다른 suspend function에서만 호출 가능.
CoroutineScope — 코루틴의 범위. CoroutineContext(Job + Dispatcher)를 포함. lifecycleScope — Activity/Fragment용(Lifecycle-aware). viewModelScope — ViewModel용(onCleared()에서 자동 취소). GlobalScope — 전역 범위(프로덕션에서 사용하지 말 것 — 메모리 누수). Dispatchers: Dispatchers.Main(UI), Dispatchers.IO(네트워크/디스크), Dispatchers.Default(CPU 집약적), Dispatchers.Unconfined(권장하지 않음). launch — 코루틴 시작: Job. async — 결과와 함께 시작: Deferred<T>. runBlocking — 블로킹 브리지. withContext — suspend 함수 내에서 Dispatcher 전환.
// 코루틴 예제: ViewModel에서 데이터 로드
class MainViewModel : ViewModel() {
private val _state = MutableStateFlow<UiState>(UiState.Loading)
val state: StateFlow<UiState> = _state.asStateFlow()
fun loadData() {
viewModelScope.launch {
_state.value = UiState.Loading
try {
val data = withContext(Dispatchers.IO) {
repository.fetchData()
}
_state.value = UiState.Success(data)
} catch (e: Exception) {
_state.value = UiState.Error(e.message)
}
}
}
}
// async를 사용한 병렬 요청
suspend fun loadCombinedData(): CombinedData = coroutineScope {
val users = async(Dispatchers.IO) { api.getUsers() }
val posts = async(Dispatchers.IO) { api.getPosts() }
CombinedData(users.await(), posts.await())
}viewModelScope.launch — ViewModel에서 표준 코루틴 실행. withContext(Dispatchers.IO) — 네트워크 요청을 위해 IO 스레드로 전환. Dispatchers는 코루틴이 실행될 스레드 풀을 결정합니다. IT Sectr는 ViewModel에는 viewModelScope, Activity/Fragment에는 lifecycleScope를 권장합니다.
reified — inline 함수의 타입 수정자. 타입 사용 가능: T::class, is T, as T. reified 없이 JVM의 제네릭은 소거됨(type erasure). inline fun + reified — 타입 안전 API를 위한 강력한 조합. Destructuring Declaration — val (x, y) = point. data class 및 componentN()이 있는 타입에서 작동. typealias — 타입 별칭: typealias Callback = (String) -> Unit. lateinit — var 지연 초기화(의존성 주입용). 스레드 안전하지 않음. lazy — val 지연 초기화(기본적으로 스레드 안전). lazy(LazyThreadSafetyMode.NONE) — 동기화 없음. Extension function 및 Extension property — 상속 없이 기능 추가. Kotlin은 extension functions가 유틸리티 작업의 90%를 해결하는 언어입니다.
Delegated Properties — getter/setter를 다른 객체에 위임. 표준 위임자: lazy, observable, vetoable, map. getValue/setValue 연산자를 통한 사용자 정의 위임자. by — 위임 키워드: val name by lazy { loadName() }. 위임 속성은 ViewModel 위임자(by viewModels())의 기초입니다. IT Sectr는 지연 초기화에는 lazy, 변경 관찰에는 Delegates.observable을 권장합니다.
| 기능 | 설명 | 예제 |
|---|---|---|
| reified | inline에서 제네릭 타입 보존 | inline fun <reified T> parse(): T |
| destructuring | data class 분해 | val (name, age) = person |
| typealias | 타입 별칭 | typealias Orders = List<Order> |
| lateinit | var 지연 초기화 | lateinit var adapter: Adapter |
| lazy | val 지연 초기화 | val config by lazy { load() } |
| delegated | 속성 위임 | var x by Delegates.observable(0) |
reified — 타입 안전 API용. lazy — 지연 로딩용. delegated properties — 속성 로직 재사용용. IT Sectr는 효과적인 Kotlin 개발을 위해 이러한 모든 기능을 숙지할 것을 권장합니다.
Flow — Kotlin의 콜드 비동기 데이터 스트림. 수집기의 요청에 따라 값을 방출. StateFlow — 단일 현재 값을 가진 핫 Flow. ViewModel에서 UI State에 사용. SharedFlow — 이벤트용 핫 Flow(원샷 이벤트). flowOf, asFlow — 컬렉션에서 Flow 생성. catch, retry, debounce — 연산자. stateIn, shareIn — 콜드 Flow를 핫으로 변환. IT Sectr는 UI State에는 StateFlow, 이벤트(Snackbar, 탐색)에는 SharedFlow를 권장합니다.
class SearchViewModel : ViewModel() {
private val _query = MutableStateFlow("")
val suggestions: StateFlow<List<String>> = _query
.debounce(300)
.filter { it.length >= 2 }
.flatMapLatest { repository.search(it) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
fun onQueryChanged(query: String) {
_query.value = query
}
}kotlinx.serialization — JSON 직렬화를 위한 Kotlin 라이브러리. @Serializable — 어노테이션. @SerialName — 사용자 정의 필드 이름. 지원: JSON, CBOR, ProtoBuf. Parcelize — Android Parcelable용 @Parcelize(수동 구현 불필요). Gson vs Moshi vs kotlinx: kotlinx.serialization — Kotlin 우선, 컴파일 안전, 리플렉션 불필요. Moshi — 어노테이션 + codegen. IT Sectr는 새 프로젝트에는 kotlinx.serialization, 기존 프로젝트에는 Moshi를 권장합니다.
@Serializable
data class ApiResponse<T>(
val success: Boolean,
@SerialName("data") val data: T? = null,
val error: String? = null
)
@Serializable
data class User(
val id: Int,
val name: String,
val email: String
)
// 역직렬화
val json = Json { ignoreUnknownKeys = true }
val response = json.decodeFromString<ApiResponse<List<User>>>(jsonString)
println("Users: ${response.data?.size ?: 0}")자주 묻는 질문
data class — 데이터용(equals/hashCode/copy 자동 생성). sealed class — 타입 계층용(when 검사). sealed interface — 다중 상속 지원.
let, run, with, apply, also. 컨텍스트(it vs this)와 반환값(result vs context)으로 구분. let — null 안전, apply — 구성, also — 부작용.
CoroutineScope — 코루틴의 범위. lifecycleScope — Activity용, viewModelScope — ViewModel용. GlobalScope — 권장되지 않음.
reified — inline 함수에서 타입 보존. T::class 및 is T 허용. inline 함수에서만 작동.
launch — 결과 없음. async — 결과 있음(Deferred). runBlocking — main/test용 블로킹 브리지. withContext — Dispatcher 전환.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.