# 코틀린 전체 문법 정리
## 1. 기본 구조
### Hello World
```kotlin
fun main() {
println("Hello, World!")
}
// 또는 매개변수가 있는 main
fun main(args: Array<String>) {
println("Hello, ${args.firstOrNull() ?: "World"}!")
}
```
### 패키지와 임포트
```kotlin
package com.example.myapp
import kotlin.math.*
import java.util.Date as JavaDate
import com.example.utils.* // 모든 것 임포트
```
## 2. 변수와 상수
### val vs var
```kotlin
val name = "홍길동" // 불변(읽기 전용) - Java의 final
var age = 25 // 가변
val PI: Double = 3.14 // 타입 명시
var count: Int // 선언만 (나중에 초기화)
count = 10
```
### 늦은 초기화
```kotlin
lateinit var userName: String // 나중에 초기화 (var만 가능)
val lazyValue: String by lazy { // 처음 사용할 때 초기화
"Heavy computation result"
}
```
## 3. 데이터 타입
### 기본 타입
```kotlin
// 정수
val byte: Byte = 127
val short: Short = 32767
val int: Int = 2147483647
val long: Long = 9223372036854775807L
// 실수
val float: Float = 3.14f
val double: Double = 3.14159
// 문자와 문자열
val char: Char = 'A'
val string: String = "Hello"
// 불린
val boolean: Boolean = true
// 배열
val array = arrayOf(1, 2, 3)
val intArray = intArrayOf(1, 2, 3)
```
### 타입 변환
```kotlin
val i: Int = 100
val l: Long = i.toLong()
val d: Double = i.toDouble()
val s: String = i.toString()
// 안전한 캐스팅
val obj: Any = "Hello"
val str: String? = obj as? String // 실패하면 null
```
## 4. 문자열
### 문자열 템플릿
```kotlin
val name = "홍길동"
val age = 25
println("이름: $name") // 간단한 변수
println("내년 나이: ${age + 1}") // 표현식
println("이름 길이: ${name.length}") // 프로퍼티 접근
```
### 원시 문자열
```kotlin
val multiLine = """
첫 번째 줄
두 번째 줄
세 번째 줄
""".trimIndent()
val regex = """\\d{3}-\\d{4}-\\d{4}""" // 이스케이프 불필요
```
## 5. 함수
### 기본 함수
```kotlin
fun add(a: Int, b: Int): Int {
return a + b
}
// 단일 표현식 함수
fun multiply(a: Int, b: Int) = a * b
// 매개변수 기본값
fun greet(name: String = "World") = "Hello, $name!"
// 명명된 인수
greet(name = "Kotlin")
```
### 다양한 매개변수
```kotlin
// 가변 인수
fun sum(vararg numbers: Int): Int {
return numbers.sum()
}
sum(1, 2, 3, 4, 5)
// 확장 연산자
val array = intArrayOf(1, 2, 3)
sum(*array) // 배열을 개별 인수로 전달
```
### 고차 함수
```kotlin
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}
val result = calculate(5, 3) { a, b -> a + b } // 람다
// 함수 타입 변수
val operation: (Int, Int) -> Int = { a, b -> a * b }
```
### 확장 함수
```kotlin
// String에 확장 함수 추가
fun String.isPalindrome(): Boolean {
return this == this.reversed()
}
"level".isPalindrome() // true
// 제네릭 확장 함수
fun <T> List<T>.secondOrNull(): T? {
return if (size >= 2) this[1] else null
}
```
### 인라인 함수
```kotlin
inline fun <T> measure(action: () -> T): T {
val start = System.currentTimeMillis()
val result = action()
println("Execution time: ${System.currentTimeMillis() - start}ms")
return result
}
```
## 6. 클래스와 객체
### 기본 클래스
```kotlin
class Person(val name: String, var age: Int) {
// 보조 생성자
constructor(name: String) : this(name, 0)
// 초기화 블록
init {
println("Person created: $name")
}
// 메서드
fun introduce() = "안녕하세요, 저는 $name이고 ${age}살입니다."
}
val person = Person("홍길동", 25)
```
### 프로퍼티
```kotlin
class Rectangle(val width: Int, val height: Int) {
// 계산된 프로퍼티
val area: Int
get() = width * height
// 커스텀 getter/setter
var isSquare: Boolean
get() = width == height
set(value) {
if (value) {
// 정사각형으로 만들기
}
}
// 뒷받침 필드가 있는 프로퍼티
var name: String = ""
set(value) {
field = value.uppercase() // field는 뒷받침 필드
}
}
```
### 상속
```kotlin
// 기본 클래스 (open으로 상속 허용)
open class Animal(val name: String) {
open fun sound() = "Some sound"
// final로 오버라이드 금지
final fun sleep() = "$name is sleeping"
}
class Dog(name: String, val breed: String) : Animal(name) {
override fun sound() = "Woof!"
fun wagTail() = "$name is wagging tail"
}
// 추상 클래스
abstract class Shape {
abstract fun area(): Double
// 구체적인 메서드도 가질 수 있음
fun description() = "This is a shape"
}
class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
}
```
### 데이터 클래스
```kotlin
data class User(val name: String, val email: String, val age: Int)
val user1 = User("홍길동", "hong@example.com", 25)
val user2 = user1.copy(age = 26) // 복사본 생성
// 자동 생성되는 메서드들
println(user1.toString()) // User(name=홍길동, email=hong@example.com, age=25)
println(user1 == user2) // false (구조적 동등성)
println(user1.hashCode()) // 해시코드
// 구조 분해
val (name, email, age) = user1
```
### 봉인 클래스 (Sealed Class)
```kotlin
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
}
fun handleResult(result: Result) = when (result) {
is Result.Success -> "데이터: ${result.data}"
is Result.Error -> "오류: ${result.message}"
Result.Loading -> "로딩 중..."
// else 불필요 (모든 경우가 처리됨)
}
```
### 열거형
```kotlin
enum class Direction {
NORTH, SOUTH, EAST, WEST
}
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF);
fun containsRed() = (this.rgb and 0xFF0000 != 0)
}
```
### 인터페이스
```kotlin
interface Drawable {
val color: String // 프로퍼티
fun draw() // 추상 메서드
// 기본 구현이 있는 메서드
fun erase() {
println("Erasing...")
}
}
class Circle : Drawable {
override val color = "Red"
override fun draw() = println("Drawing a circle")
}
```
### 객체 선언과 표현식
```kotlin
// 싱글톤 객체
object DatabaseManager {
fun connect() = println("Connected to database")
}
// 익명 객체 (Java의 익명 클래스)
val clickListener = object : View.OnClickListener {
override fun onClick(v: View?) {
println("Clicked!")
}
}
// 동반 객체 (Java의 static 유사)
class MyClass {
companion object {
const val CONSTANT = "value"
fun create() = MyClass()
}
}
```
## 7. 널 안전성
### 널 가능 타입
```kotlin
var name: String = "홍길동" // 널 불가
var nullableName: String? = null // 널 가능
// 안전 호출 연산자
val length = nullableName?.length
// 엘비스 연산자
val len = nullableName?.length ?: 0
// 확정 연산자 (!! - 주의해서 사용)
val definiteLength = nullableName!!.length // null이면 예외
// 안전 캐스트
val str: String? = obj as? String
```
### 스코프 함수와 널 처리
```kotlin
val person: Person? = getPerson()
person?.let { p ->
println("이름: ${p.name}")
println("나이: ${p.age}")
}
// run with 널 체크
person?.run {
println("이름: $name")
println("나이: $age")
}
```
## 8. 컬렉션
### 리스트
```kotlin
// 불변 리스트
val fruits = listOf("apple", "banana", "orange")
val numbers = listOf(1, 2, 3, 4, 5)
// 가변 리스트
val mutableFruits = mutableListOf("apple", "banana")
mutableFruits.add("orange")
// 배열
val array = arrayOf(1, 2, 3)
val intArray = intArrayOf(1, 2, 3) // 기본 타입 배열
```
### 세트
```kotlin
val uniqueNumbers = setOf(1, 2, 3, 3, 2) // [1, 2, 3]
val mutableSet = mutableSetOf<String>()
```
### 맵
```kotlin
val ages = mapOf(
"홍길동" to 25,
"김철수" to 30,
"이영희" to 28
)
val mutableAges = mutableMapOf<String, Int>()
mutableAges["박민수"] = 32
```
### 컬렉션 연산
```kotlin
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val evenNumbers = numbers.filter { it % 2 == 0 }
val doubled = numbers.map { it * 2 }
val sum = numbers.reduce { acc, n -> acc + n }
val fold = numbers.fold(0) { acc, n -> acc + n }
// 체이닝
val result = numbers
.filter { it % 2 == 0 }
.map { it * 2 }
.take(3)
.sum()
// 그룹화
val words = listOf("apple", "banana", "apricot", "blueberry")
val grouped = words.groupBy { it.first() } // {a=[apple, apricot], b=[banana, blueberry]}
```
## 9. 제어 구조
### 조건문
```kotlin
// if 표현식
val max = if (a > b) a else b
val result = if (x > 0) {
println("Positive")
"positive"
} else if (x < 0) {
println("Negative")
"negative"
} else {
println("Zero")
"zero"
}
```
### when 표현식
```kotlin
val x = 3
val result = when (x) {
1 -> "One"
2, 3 -> "Two or Three"
in 4..10 -> "Between 4 and 10"
is Int -> "It's an integer"
else -> "Something else"
}
// 조건 없는 when
val score = 85
val grade = when {
score >= 90 -> "A"
score >= 80 -> "B"
score >= 70 -> "C"
else -> "F"
}
```
### 반복문
```kotlin
// for 루프
for (i in 1..5) {
println(i) // 1, 2, 3, 4, 5
}
for (i in 1 until 5) {
println(i) // 1, 2, 3, 4
}
for (i in 5 downTo 1 step 2) {
println(i) // 5, 3, 1
}
// 컬렉션 반복
val fruits = listOf("apple", "banana", "orange")
for (fruit in fruits) {
println(fruit)
}
for ((index, fruit) in fruits.withIndex()) {
println("$index: $fruit")
}
// while 루프
var i = 0
while (i < 5) {
println(i++)
}
do {
println("At least once")
} while (false)
```
### 반복 제어
```kotlin
for (i in 1..10) {
if (i % 2 == 0) continue
if (i > 7) break
println(i)
}
// 라벨을 사용한 제어
outer@ for (i in 1..3) {
inner@ for (j in 1..3) {
if (i == 2 && j == 2) break@outer
println("$i, $j")
}
}
```
## 10. 예외 처리
```kotlin
fun divide(a: Int, b: Int): Int {
return try {
a / b
} catch (e: ArithmeticException) {
println("Division by zero!")
0
} catch (e: Exception) {
println("General error: ${e.message}")
-1
} finally {
println("Division operation completed")
}
}
// 예외 던지기
fun validateAge(age: Int) {
if (age < 0) {
throw IllegalArgumentException("Age cannot be negative")
}
}
// Nothing 타입
fun fail(message: String): Nothing {
throw IllegalStateException(message)
}
```
## 11. 람다와 고차 함수
### 람다 표현식
```kotlin
val sum = { x: Int, y: Int -> x + y }
val square: (Int) -> Int = { it * it } // 단일 매개변수는 it
// 후행 람다
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
val filtered = numbers.filter { number ->
number % 2 == 0
}
```
### 스코프 함수
```kotlin
data class Person(var name: String, var age: Int)
val person = Person("홍길동", 25)
// let - 널 체크와 변환
person.let { p ->
println("${p.name} is ${p.age} years old")
}
// run - 객체 구성과 결과 계산
val result = person.run {
name = "김철수"
age = 30
"Updated person: $name, $age" // 반환값
}
// with - 객체와 함께 작업
val description = with(person) {
"Name: $name, Age: $age"
}
// apply - 객체 구성
val newPerson = Person("이영희", 28).apply {
age = 29
name = "이영희(수정)"
}
// also - 추가 작업
val anotherPerson = Person("박민수", 32).also { p ->
println("Created person: ${p.name}")
}
```
## 12. 제네릭
### 기본 제네릭
```kotlin
class Box<T>(val item: T) {
fun get(): T = item
}
val stringBox = Box("Hello")
val intBox = Box(42)
// 제네릭 함수
fun <T> swap(list: MutableList<T>, i: Int, j: Int) {
val temp = list[i]
list[i] = list[j]
list[j] = temp
}
```
### 변성 (Variance)
```kotlin
// 공변성 (out)
interface Producer<out T> {
fun produce(): T
}
// 반공변성 (in)
interface Consumer<in T> {
fun consume(item: T)
}
// 불변성
interface Processor<T> {
fun process(item: T): T
}
// 사용 지점 변성
fun copy(from: Array<out Any>, to: Array<in Any>) {
// from은 읽기만, to는 쓰기만
}
```
### 제약 조건
```kotlin
// 상한 경계
fun <T : Number> sum(list: List<T>): Double {
return list.sumOf { it.toDouble() }
}
// 여러 제약 조건
fun <T> process(item: T) where T : Comparable<T>, T : Serializable {
// T는 Comparable이면서 Serializable이어야 함
}
```
## 13. 위임
### 클래스 위임
```kotlin
interface Base {
fun doSomething()
}
class BaseImpl : Base {
override fun doSomething() = println("BaseImpl doing something")
}
class Derived(base: Base) : Base by base {
// Base의 구현을 base에게 위임
}
val derived = Derived(BaseImpl())
derived.doSomething() // BaseImpl의 구현 호출
```
### 프로퍼티 위임
```kotlin
import kotlin.properties.Delegates
class User {
// 지연 초기화
val name: String by lazy {
println("Computing name...")
"홍길동"
}
// 관찰 가능한 프로퍼티
var age: Int by Delegates.observable(0) { property, oldValue, newValue ->
println("$oldValue -> $newValue")
}
// 맵에 위임
val properties = mapOf("email" to "hong@example.com")
val email: String by properties
}
```
## 14. 코루틴 (기본)
suspend는 함수를 중단했다가 다시 실행할 수 있도록 만들어 비동기 처리를 지원한다. 예를 들어, 아래 예제에서 fetchData 함수에 suspend를 붙임으로써 data 처리 작업과 다른 ui 작업 등을 교차로 수행할 수 있다.
```kotlin
import kotlinx.coroutines.*
// 기본 코루틴
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
// async와 await
suspend fun fetchData(): String {
delay(1000L)
return "Data"
}
fun main() = runBlocking {
val deferred = async { fetchData() }
println("Waiting...")
val result = deferred.await()
println("Result: $result")
}
```
## 15. 애노테이션과 리플렉션
### 애노테이션
```kotlin
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class MyAnnotation(val value: String)
@MyAnnotation("test")
class TestClass {
@MyAnnotation("method")
fun testMethod() {}
}
```
### 리플렉션
```kotlin
import kotlin.reflect.full.*
class Person(val name: String, val age: Int)
val person = Person("홍길동", 25)
val kClass = person::class
// 클래스 정보
println("Class name: ${kClass.simpleName}")
println("Properties: ${kClass.memberProperties.map { it.name }}")
// 프로퍼티 접근
val nameProperty = kClass.memberProperties.find { it.name == "name" }
val nameValue = nameProperty?.get(person)
```