Kotlin 변수와 타입 | val, var, 기본 타입 완벽 정리
이 글의 핵심
Kotlin 변수와 타입에 대해 정리한 개발 블로그 글입니다. var score = 90 score = 95
들어가며
val·var와 널 안전성(?, !!, ?.)으로 불변을 기본에 두고, 널 가능성을 타입에 적습니다. 컴파일러가 흐름 분석으로 불필요한 null 검사를 줄여 줍니다.
1. 변수 선언
val (불변)
val name = "홍길동"
val age = 25
// name = "김철수" // 컴파일 에러!
var (가변)
var score = 90
score = 95 // OK
var count = 0
count++ // OK
선택 기준
// 기본적으로 val 사용 (권장)
val pi = 3.14
val maxSize = 100
// 변경이 필요한 경우만 var
var currentPage = 1
var isLoggedIn = false
2. 기본 타입
숫자 타입
// 정수
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
문자와 문자열
// 문자
val char: Char = 'A'
val koreanChar = '가'
// 문자열
val text: String = "Hello"
val multiLine = """
여러 줄
문자열
""".trimIndent()
// 문자열 템플릿
val name = "홍길동"
val greeting = "안녕하세요, $name님!"
val info = "나이: ${age + 1}세"
불리언
val isActive: Boolean = true
val isCompleted = false
// 논리 연산
val result = isActive && !isCompleted
3. Nullable 타입
Non-null vs Nullable
// Non-null (기본)
var name: String = "홍길동"
// name = null // 컴파일 에러!
// Nullable
var nullableName: String? = "홍길동"
nullableName = null // OK
Safe Call (?.)
Nullable 타입을 안전하게 다루는 핵심 연산자입니다:
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일 때 기본값을 제공하는 연산자입니다:
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이 아니다”라고 컴파일러에게 단언합니다:
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 Call | null 반환 |
?: | Elvis | 기본값 반환 |
!! | Not-null 단언 | 예외 발생 |
Safe Cast (as?)
val obj: Any = "Hello"
val str: String? = obj as? String // 성공
val num: Int? = obj as? Int // null 반환
4. 타입 변환
명시적 변환
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()
문자열 변환
// 문자열 → 숫자
val str = "123"
val num = str.toInt()
val decimal = str.toDouble()
// 안전한 변환
val num = str.toIntOrNull() ?: 0
5. 타입 체크와 스마트 캐스트
is 연산자
val obj: Any = "Hello"
if (obj is String) {
// 자동으로 String으로 캐스트
println(obj.length)
}
// not is
if (obj !is String) {
println("문자열이 아님")
}
when과 스마트 캐스트
fun describe(obj: Any): String {
return when (obj) {
is String -> "문자열, 길이: ${obj.length}"
is Int -> "정수: $obj"
is List<*> -> "리스트, 크기: ${obj.size}"
else -> "알 수 없음"
}
}
6. 상수
const val
// 컴파일 타임 상수
const val MAX_SIZE = 100
const val API_KEY = "your-api-key"
// 클래스 밖에서만 선언 가능
class Config {
companion object {
const val TIMEOUT = 5000
}
}
lateinit
// 나중에 초기화
class MyClass {
lateinit var name: String
fun init() {
name = "홍길동"
}
fun isInitialized() = ::name.isInitialized
}
lazy
// 처음 사용 시 초기화
val heavyObject: HeavyObject by lazy {
println("초기화 중...")
HeavyObject()
}
// 처음 접근 시에만 초기화됨
println(heavyObject.data)
7. 실전 예제
예제 1: 사용자 입력 처리
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: 타입 변환 유틸리티
fun parseNumber(input: String): Int {
return input.toIntOrNull() ?: run {
println("잘못된 입력: $input")
0
}
}
fun main() {
println(parseNumber("123")) // 123
println(parseNumber("abc")) // 0
}
정리
핵심 요약
- val: 불변 (권장)
- var: 가변
- Nullable:
String?,?.,?:,!! - 타입 변환:
toInt(),toString() - 스마트 캐스트:
is연산자 - 지연 초기화:
lateinit,lazy
다음 단계
- Kotlin 함수
- Kotlin 클래스
- Kotlin 컬렉션
관련 글
- Java 변수와 타입 | 기본 타입, 참조 타입, 형변환
- JavaScript 변수와 데이터 타입 | let, const, var 완벽 정리
- Swift 변수와 타입 | var, let, 옵셔널
- C++ numeric_limits |
- C++ 템플릿 |