[2026] Kotlin 변수와 타입 | val, var, 기본 타입 완벽 정리

[2026] Kotlin 변수와 타입 | val, var, 기본 타입 완벽 정리

이 글의 핵심

var score = 90 score = 95.

들어가며

val·var널 안전성(?, !!, ?.)으로 불변을 기본에 두고, 널 가능성을 타입에 적습니다. 컴파일러가 흐름 분석으로 불필요한 null 검사를 줄여 줍니다.

실무에서 마주한 현실

개발을 배울 때는 모든 게 깔끔하고 이론적입니다. 하지만 실무는 다릅니다. 레거시 코드와 씨름하고, 급한 일정에 쫓기고, 예상치 못한 버그와 마주합니다. 이 글에서 다루는 내용도 처음엔 이론으로 배웠지만, 실제 프로젝트에 적용하면서 “아, 이래서 이렇게 설계하는구나” 하고 깨달은 것들입니다. 특히 기억에 남는 건 첫 프로젝트에서 겪은 시행착오입니다. 책에서 배운 대로 했는데 왜 안 되는지 몰라 며칠을 헤맸죠. 결국 선배 개발자의 코드 리뷰를 통해 문제를 발견했고, 그 과정에서 많은 걸 배웠습니다. 이 글에서는 이론뿐 아니라 실전에서 마주칠 수 있는 함정들과 해결 방법을 함께 다루겠습니다.

1. 변수 선언

val (불변)

val name = "홍길동"
val age = 25
// name = "김철수"  // 컴파일 에러!

var (가변)

아래 코드는 kotlin를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

var score = 90
score = 95  // OK
var count = 0
count++  // OK

선택 기준

아래 코드는 kotlin를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// 기본적으로 val 사용 (권장)
val pi = 3.14
val maxSize = 100
// 변경이 필요한 경우만 var
var currentPage = 1
var isLoggedIn = false

2. 기본 타입

숫자 타입

다음은 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 number = 10        // Int
val bigNumber = 10L    // Long
val decimal = 3.14     // Double
val precise = 3.14f    // Float

문자와 문자열

다음은 kotlin를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 문자
val char: Char = 'A'
val koreanChar = '가'
// 문자열
val text: String = "Hello"
val multiLine = """
    여러 줄
    문자열
""".trimIndent()
// 문자열 템플릿
val name = "홍길동"
val greeting = "안녕하세요, $name님!"
val info = "나이: ${age + 1}세"

불리언

아래 코드는 kotlin를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

val isActive: Boolean = true
val isCompleted = false
// 논리 연산
val result = isActive && !isCompleted

3. Nullable 타입

Non-null vs Nullable

아래 코드는 kotlin를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Non-null (기본)
var name: String = "홍길동"
// name = null  // 컴파일 에러!
// Nullable
var nullableName: String? = "홍길동"
nullableName = null  // OK

Safe Call (?.)

Nullable 타입을 안전하게 다루는 핵심 연산자입니다: 아래 코드는 kotlin를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

val name: String? = null
// Safe Call: null이면 null 반환, 아니면 프로퍼티/메서드 호출
val length = name?.length  
// name이 null이면 length도 null
// name이 "홍길동"이면 length는 3
// Java의 if (name != null) name.length() 를 간결하게 표현
// 체이닝 가능 - 중간에 null이 있으면 전체가 null
val city = user?.address?.city
// user가 null이면 → null
// user.address가 null이면 → null
// 둘 다 있으면 → user.address.city
// Java라면 여러 줄의 null 체크가 필요

Elvis 연산자 (?:)

null일 때 기본값을 제공하는 연산자입니다: 다음은 kotlin를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

val name: String? = null
// Elvis 연산자: null이면 오른쪽 값 사용
val length = name?.length ?: 0  
// name?.length가 null이면 0 반환
// name?.length가 3이면 3 반환
// 기본값 제공
val displayName = name ?: "Guest"
// name이 null이면 "Guest"
// name이 "홍길동"이면 "홍길동"
// 실전 예시: 사용자 이름 표시
fun greet(name: String?) {
    val greeting = "안녕하세요, ${name ?: "방문자"}님!"
    println(greeting)
}
greet(null)      // 안녕하세요, 방문자님!
greet("홍길동")  // 안녕하세요, 홍길동님!

Not-null 단언 (!!)

“이 값은 절대 null이 아니다”라고 컴파일러에게 단언합니다: 다음은 kotlin를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

val name: String? = "홍길동"
// !! : null이 아님을 단언
val length = name!!.length  
// name이 null이면 KotlinNullPointerException 발생
// name이 "홍길동"이면 3 반환
// 주의: 확실할 때만 사용!
// 가능하면 ?. 또는 ?: 사용 권장
// 나쁜 예
val user: User? = getUser()
val name = user!!.name  // null이면 크래시!
// 좋은 예
val name = user?.name ?: "Unknown"  // null 안전

연산자 비교:

연산자동작null일 때
?.Safe Callnull 반환
?:Elvis기본값 반환
!!Not-null 단언예외 발생

Safe Cast (as?)

val obj: Any = "Hello"
val str: String? = obj as? String  // 성공
val num: Int? = obj as? Int        // null 반환

4. 타입 변환

명시적 변환

아래 코드는 kotlin를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

val int: Int = 10
val long: Long = int.toLong()
val double: Double = int.toDouble()
val string: String = int.toString()
// 모든 변환 메서드
val byte = int.toByte()
val short = int.toShort()
val float = int.toFloat()

문자열 변환

아래 코드는 kotlin를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// 문자열 → 숫자
val str = "123"
val num = str.toInt()
val decimal = str.toDouble()
// 안전한 변환
val num = str.toIntOrNull() ?: 0

5. 타입 체크와 스마트 캐스트

is 연산자

아래 코드는 kotlin를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

val obj: Any = "Hello"
if (obj is String) {
    // 자동으로 String으로 캐스트
    println(obj.length)
}
// not is
if (obj !is String) {
    println("문자열이 아님")
}

when과 스마트 캐스트

아래 코드는 kotlin를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

fun describe(obj: Any): String {
    return when (obj) {
        is String -> "문자열, 길이: ${obj.length}"
        is Int -> "정수: $obj"
        is List<*> -> "리스트, 크기: ${obj.size}"
        else -> "알 수 없음"
    }
}

6. 상수

const val

아래 코드는 kotlin를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 컴파일 타임 상수
const val MAX_SIZE = 100
const val API_KEY = "your-api-key"
// 클래스 밖에서만 선언 가능
class Config {
    companion object {
        const val TIMEOUT = 5000
    }
}

lateinit

아래 코드는 kotlin를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 나중에 초기화
class MyClass {
    lateinit var name: String
    
    fun init() {
        name = "홍길동"
    }
    
    fun isInitialized() = ::name.isInitialized
}

lazy

아래 코드는 kotlin를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// 처음 사용 시 초기화
val heavyObject: HeavyObject by lazy {
    println("초기화 중...")
    HeavyObject()
}
// 처음 접근 시에만 초기화됨
println(heavyObject.data)

7. 실전 예제

예제 1: 사용자 입력 처리

아래 코드는 kotlin를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

fun main() {
    print("이름을 입력하세요: ")
    val name = readLine() ?: "Guest"
    
    print("나이를 입력하세요: ")
    val ageInput = readLine()
    val age = ageInput?.toIntOrNull() ?: 0
    
    println("안녕하세요, $name님! (${age}세)")
}

예제 2: 안전한 계산

fun divide(a: Int, b: Int): Double? {
    return if (b != 0) {
        a.toDouble() / b
    } else {
        null
    }
}
fun main() {
    val result = divide(10, 0)
    println("결과: ${result ?: "0으로 나눌 수 없음"}")
}

예제 3: 타입 변환 유틸리티

아래 코드는 kotlin를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

fun parseNumber(input: String): Int {
    return input.toIntOrNull() ?: run {
        println("잘못된 입력: $input")
    }
}
fun main() {
    println(parseNumber("123"))    // 123
    println(parseNumber("abc"))    // 0
}

정리

핵심 요약

  1. val: 불변 (권장)
  2. var: 가변
  3. Nullable: String?, ?., ?:, !!
  4. 타입 변환: toInt(), toString()
  5. 스마트 캐스트: is 연산자
  6. 지연 초기화: lateinit, lazy

다음 단계


관련 글

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3