1. 변수와 상수

var vs val

// val - 불변 변수 (immutable, 읽기 전용)
val name: String = "Kotlin"
name = "Java"  // 오류! 재할당 불가
 
// var - 가변 변수 (mutable)
var age: Int = 25
age = 26  // OK
 
// 타입 추론 (Type Inference)
val city = "Seoul"  // String으로 자동 추론
var count = 10      // Int로 자동 추론

기본 데이터 타입

// 숫자
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.14159265359
 
// 문자와 문자열
val char: Char = 'A'
val string: String = "Hello, Kotlin"
 
// 불린
val isKotlinFun: Boolean = true
 
// Null 허용
var nullableString: String? = null  // ? 붙이면 null 가능
var nonNullString: String = "Not null"  // null 불가

2. 함수

기본 함수

// 기본 함수 선언
fun sum(a: Int, b: Int): Int {
    return a + b
}
 
// 단일 표현식 함수
fun multiply(a: Int, b: Int): Int = a * b
 
// 반환 타입 추론
fun subtract(a: Int, b: Int) = a - b
 
// Unit (void와 같음) - 반환 타입 생략 가능
fun printHello() {
    println("Hello")
}
 
// 기본 매개변수
fun greet(name: String = "Guest") {
    println("Hello, $name!")
}
greet()           // "Hello, Guest!"
greet("John")     // "Hello, John!"
 
// 명명된 매개변수
fun createUser(name: String, age: Int, city: String) {
    println("$name, $age, $city")
}
createUser(name = "Alice", city = "Seoul", age = 30)

가변 인자

fun printAll(vararg messages: String) {
    for (message in messages) {
        println(message)
    }
}
printAll("Hello", "World", "Kotlin")

3. 문자열

문자열 템플릿

val name = "Kotlin"
val version = 1.9
 
// 변수 삽입
println("Language: $name")
 
// 표현식 삽입
println("Version: ${version + 0.1}")
 
// 여러 줄 문자열
val text = """
    첫 번째 줄
    두 번째 줄
    세 번째 줄
""".trimIndent()

4. 조건문

if-else

// 기본 if-else
val max = if (a > b) {
    println("a가 더 큼")
    a
} else {
    println("b가 더 크거나 같음")
    b
}
 
// 단순 if-else 표현식
val max = if (a > b) a else b
 
// if-else if-else
val grade = when {
    score >= 90 -> "A"
    score >= 80 -> "B"
    score >= 70 -> "C"
    else -> "F"
}

when (switch 대체)

// 값 매칭
val dayOfWeek = 3
val dayName = when (dayOfWeek) {
    1 -> "월요일"
    2 -> "화요일"
    3 -> "수요일"
    4 -> "목요일"
    5 -> "금요일"
    6, 7 -> "주말"
    else -> "잘못된 입력"
}
 
// 범위 체크
val age = 25
when (age) {
    in 0..12 -> println("어린이")
    in 13..19 -> println("청소년")
    in 20..64 -> println("성인")
    else -> println("노인")
}
 
// 타입 체크
fun describe(obj: Any): String = when (obj) {
    is String -> "문자열: $obj"
    is Int -> "정수: $obj"
    is Boolean -> "불린: $obj"
    else -> "알 수 없는 타입"
}

5. 반복문

for 루프

// 범위 반복
for (i in 1..5) {
    println(i)  // 1, 2, 3, 4, 5
}
 
// until (마지막 제외)
for (i in 1 until 5) {
    println(i)  // 1, 2, 3, 4
}
 
// downTo (역순)
for (i in 5 downTo 1) {
    println(i)  // 5, 4, 3, 2, 1
}
 
// step (증가값)
for (i in 0..10 step 2) {
    println(i)  // 0, 2, 4, 6, 8, 10
}
 
// 배열/리스트 반복
val fruits = listOf("Apple", "Banana", "Cherry")
for (fruit in fruits) {
    println(fruit)
}
 
// 인덱스와 함께
for ((index, fruit) in fruits.withIndex()) {
    println("$index: $fruit")
}

while 루프

// while
var count = 0
while (count < 5) {
    println(count)
    count++
}
 
// do-while
var x = 0
do {
    println(x)
    x++
} while (x < 5)

6. 컬렉션

List (리스트)

// 불변 리스트
val readOnlyList = listOf("A", "B", "C")
println(readOnlyList[0])  // A
// readOnlyList.add("D")  // 오류! 불변
 
// 가변 리스트
val mutableList = mutableListOf("A", "B", "C")
mutableList.add("D")
mutableList.remove("A")
mutableList[0] = "Z"
 
// 리스트 연산
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers.first())     // 1
println(numbers.last())      // 5
println(numbers.size)        // 5
println(numbers.contains(3)) // true

Set (집합)

// 불변 집합
val readOnlySet = setOf(1, 2, 3, 2, 1)  // 중복 제거됨
println(readOnlySet)  // [1, 2, 3]
 
// 가변 집합
val mutableSet = mutableSetOf("A", "B", "C")
mutableSet.add("D")
mutableSet.remove("A")

Map (맵)

// 불변 맵
val readOnlyMap = mapOf(
    "name" to "John",
    "age" to 30,
    "city" to "Seoul"
)
println(readOnlyMap["name"])  // John
 
// 가변 맵
val mutableMap = mutableMapOf<String, Int>()
mutableMap["apple"] = 1000
mutableMap["banana"] = 500
mutableMap.remove("apple")
 
// 맵 순회
for ((key, value) in readOnlyMap) {
    println("$key: $value")
}

7. Null 안전성

Null 처리

// Nullable 타입
var name: String? = null
 
// Safe Call (?.)
val length = name?.length  // name이 null이면 null 반환
 
// Elvis 연산자 (?:)
val length = name?.length ?: 0  // null이면 0 반환
 
// Non-null 단언 (!!)
val length = name!!.length  // null이면 예외 발생 (권장 안 함)
 
// let 함수
name?.let {
    println("이름: $it")  // name이 null이 아닐 때만 실행
}

8. 클래스와 객체

기본 클래스

// 기본 클래스
class Person {
    var name: String = ""
    var age: Int = 0
 
    fun introduce() {
        println("이름: $name, 나이: $age")
    }
}
 
val person = Person()
person.name = "John"
person.age = 30
person.introduce()

생성자

// 주 생성자 (Primary Constructor)
class Person(val name: String, var age: Int) {
    init {
        println("Person 객체 생성: $name")
    }
 
    fun introduce() {
        println("이름: $name, 나이: $age")
    }
}
 
val person = Person("Alice", 25)
 
// 부 생성자 (Secondary Constructor)
class Person(val name: String) {
    var age: Int = 0
 
    constructor(name: String, age: Int) : this(name) {
        this.age = age
    }
}

데이터 클래스

// 데이터 클래스 (equals, hashCode, toString, copy 자동 생성)
data class User(val name: String, val age: Int)
 
val user1 = User("Alice", 25)
val user2 = User("Alice", 25)
println(user1 == user2)  // true (내용 비교)
 
// copy (복사)
val user3 = user1.copy(age = 26)
 
// 구조 분해
val (name, age) = user1
println("$name, $age")

상속

// open 키워드로 상속 가능하게 만듦
open class Animal(val name: String) {
    open fun sound() {
        println("동물 소리")
    }
}
 
class Dog(name: String) : Animal(name) {
    override fun sound() {
        println("멍멍!")
    }
}
 
val dog = Dog("바둑이")
dog.sound()  // "멍멍!"

인터페이스

interface Clickable {
    fun click()
    fun showOff() = println("Clickable!")  // 기본 구현 가능
}
 
class Button : Clickable {
    override fun click() {
        println("버튼 클릭됨")
    }
}

9. 확장 함수

// String에 확장 함수 추가
fun String.addExclamation(): String {
    return this + "!"
}
 
val message = "Hello"
println(message.addExclamation())  // "Hello!"
 
// Int에 확장 함수 추가
fun Int.isEven(): Boolean {
    return this % 2 == 0
}
 
println(4.isEven())  // true

10. 람다와 고차 함수

람다 표현식

// 기본 람다
val sum = { a: Int, b: Int -> a + b }
println(sum(3, 5))  // 8
 
// 타입 추론
val multiply: (Int, Int) -> Int = { a, b -> a * b }
 
// it (매개변수가 1개일 때)
val square: (Int) -> Int = { it * it }
println(square(5))  // 25

고차 함수

// 함수를 매개변수로 받는 함수
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}
 
val result = calculate(10, 5) { x, y -> x + y }
println(result)  // 15
 
// filter, map, reduce
val numbers = listOf(1, 2, 3, 4, 5)
 
val evenNumbers = numbers.filter { it % 2 == 0 }  // [2, 4]
val doubled = numbers.map { it * 2 }              // [2, 4, 6, 8, 10]
val sum = numbers.reduce { acc, num -> acc + num } // 15

11. 스코프 함수

let

val name: String? = "Kotlin"
name?.let {
    println("이름 길이: ${it.length}")
}

apply

val person = Person().apply {
    name = "John"
    age = 30
}

with

val person = Person()
with(person) {
    name = "Alice"
    age = 25
    introduce()
}

run

val result = person.run {
    name = "Bob"
    age = 35
    "설정 완료"  // 반환값
}

also

val numbers = mutableListOf(1, 2, 3)
    .also { println("요소 추가 전: $it") }
    .also { it.add(4) }
    .also { println("요소 추가 후: $it") }

12. 예외 처리

// try-catch
fun divide(a: Int, b: Int): Int {
    return try {
        a / b
    } catch (e: ArithmeticException) {
        println("0으로 나눌 수 없습니다")
        0
    } finally {
        println("연산 종료")
    }
}
 
// throw
fun checkAge(age: Int) {
    if (age < 0) {
        throw IllegalArgumentException("나이는 음수일 수 없습니다")
    }
}

13. 범위와 진행

// 범위 생성
val range1 = 1..10        // 1부터 10까지 (10 포함)
val range2 = 1 until 10   // 1부터 9까지 (10 미포함)
val range3 = 10 downTo 1  // 10부터 1까지 역순
 
// in 연산자
val x = 5
if (x in 1..10) {
    println("범위 안에 있음")
}
 
// !in 연산자
if (x !in 11..20) {
    println("범위 밖에 있음")
}

14. 유용한 함수들

컬렉션 함수

val numbers = listOf(1, 2, 3, 4, 5)
 
// forEach
numbers.forEach { println(it) }
 
// filter
val evens = numbers.filter { it % 2 == 0 }
 
// map
val squared = numbers.map { it * it }
 
// any, all, none
numbers.any { it > 3 }    // true (하나라도 조건 만족)
numbers.all { it > 0 }    // true (모두 조건 만족)
numbers.none { it < 0 }   // true (모두 조건 불만족)
 
// find
val firstEven = numbers.find { it % 2 == 0 }  // 2
 
// groupBy
val words = listOf("a", "ab", "abc", "abcd")
val byLength = words.groupBy { it.length }
// {1=[a], 2=[ab], 3=[abc], 4=[abcd]}
 
// sortedBy
val sorted = numbers.sortedBy { it }  // 오름차순
val sortedDesc = numbers.sortedByDescending { it }  // 내림차순

15. Pair와 Triple

// Pair
val pair = Pair("Name", "Kotlin")
// 또는
val pair = "Name" to "Kotlin"
 
println(pair.first)   // Name
println(pair.second)  // Kotlin
 
// 구조 분해
val (key, value) = pair
 
// Triple
val triple = Triple("Kotlin", 1.9, true)
println(triple.first)   // Kotlin
println(triple.second)  // 1.9
println(triple.third)   // true

16. 연산자 오버로딩

data class Point(val x: Int, val y: Int) {
    operator fun plus(other: Point): Point {
        return Point(x + other.x, y + other.y)
    }
}
 
val p1 = Point(10, 20)
val p2 = Point(5, 15)
val p3 = p1 + p2  // Point(15, 35)

17. sealed class

// sealed class (제한된 클래스 계층)
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 -> println("성공: ${result.data}")
        is Result.Error -> println("오류: ${result.message}")
        is Result.Loading -> println("로딩 중...")
    }
}

18. object (싱글톤)

// object 선언 (싱글톤)
object DatabaseManager {
    fun connect() {
        println("데이터베이스 연결")
    }
}
 
DatabaseManager.connect()
 
// companion object (정적 멤버)
class MyClass {
    companion object {
        const val CONSTANT = "상수"
        fun create() = MyClass()
    }
}
 
println(MyClass.CONSTANT)
val instance = MyClass.create()

참고 자료