Kotlin Docs | Kotlin
kotlinlang.org
프로젝트를 코틀린으로 전환한 이후 문법 공부를 위해 코틀린의 공식문서를 쭉 읽으면서 자바와는 달랐던 것, 코틀린의 신기한 것들을
위주로 정리하기로 하였습니다.
Smart casts
코틀린에서는 is 키워드를 통해 객체가 특정 타입인지 확인할 수 있습니다.
if (obj is String) {
println("obj is String")
}
if문을 만족한다면 obj라는 객체는 String 타입이란게 확실하다는 것이죠.
fun demo(x: Any) {
if (x is String) {
print(x.length) // x is automatically cast to String
}
}
위 코드처럼 컴파일러가 특정 객체의 타입을 추적하여 객체를 캐스팅해주게 됩니다.
따라서 별도의 형변환 없이 Any-> String이 되어 length 메서드를 사용할 수 있고 이걸 코틀린의 Smart casts라고 합니다.
public void demo(Object obj) {
if (obj instanceof String) {
((String) obj).length();
}
}
자바였다면 instanceof을 통해서 String 타입인 것을 확신할 수 있지만 명시적 형변환을 해야 했을겁니다.
class Cat {
fun purr() {
println("Purr purr")
}
}
fun petAnimal(animal: Any) {
val isCat = animal is Cat
if (isCat) {
animal.purr()
}
}
공식문서의 위 예제처럼 is의 결과를 의미가 있는 이름의 변수 담는 경우에도 smart casts가 동작됩니다.
isCat라는 변수에 결과를 담은 후 if을 만족한다면 컴파일러는 animal이 Cat임을 확신할 수 있습니다.
이러한 smart casts가 동작하는 조건이 있습니다.
val - 지역 변수 : 위임 프로퍼티를 제외하고 동작
val - 프로퍼티 : private, internal 키워드로 정의되어 있거나, 같은 모듈안에서 접근하는 경우 동작, open 키워드가 사용되거나 Custom getter가 등록된 경우 불가
var - 지역 변수 : 값이 변경되지 않는다면 사용 가능, lambda 내에서 값을 변경하는 것이 감지되거나 위임 프로퍼티라면 사용 불가
var - 프로퍼티 : 불가
위 조건의 공통점은 값이 변경되지 않는 것을 중요시한다는 점인데요.
class Person {
var age: Int? = 0
fun toNull() {
age = null
}
}
fun main() {
val person = Person()
val isInt = person.age is Int
person.toNull()
if (isInt) {
person.age // age is null
}
}
처음에 age is Int의 결과는 true이지만 이후 toNull 메서드를 이용해서 age를 null 로 바꾼다면 isInt는 true임에도 불구하고
age는 null이게 됩니다.
이러한 상황을 방지하기 위해 값의 변화가 감지된다면 컴파일러는 smart casts를 수행하지 않습니다.
조건에서 언급되는 프로퍼티, 위임 프로퍼티라는 개념도 나중에 따로 정리하겠지만 지금은 간단하게 별도의 메서드를 통해 값을 조회하고 수정해야하는 변수라고 생각하면 될 것 같습니다. 별도의 메서드가 어떻게 구현되었느냐에 따라 다르겠지만 같은 조건임에도 불구하고 다른 값을 반환할 수 있기 때문에 즉 값이 변할 수 있기 때문에 custom getter 혹은 위임 프로퍼티를 사용하는 경우 smart casts가 동작하지
않는다고 볼 수 있습니다.
If expression
코틀린에서 if문은 값을 리턴해 줄 수 있습니다.
fun main() {
val a = 10
val b = 20
val c = if (a > b) a else b
println(c) // 20
}
자바의 경우 삼항 연산자를 통해 처리를 했겠지만 코틀린은 if문을 통해 특정 변수의 값을 할당해줄 수 있습니다.
주의점은 위 코드처럼 if문을 통해 변수의 값을 설정하거나 리턴해주는 경우 else는 필수입니다. (모든 상황에서 값을 리턴해줘야하기 때문)
When expressions and statements
코틀린에서 when문은 Java의 switch문과 비슷합니다.
val x = 2
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> print("x is neither 1 nor 2")
}
조건을 설정하고 subject(x)가 해당하는 조건으로 분기할 수 있습니다.
val text = when (x) {
1 -> "x == 1"
2 -> "x == 2"
else -> "x is neither 1 nor 2"
}
when문 또한 값을 리턴해줄 수 있기 때문에 변수에 값을 할당하는 데 사용될 수 있습니다.
when {
a > b -> "a is greater than b"
a < b -> "a is less than b"
else -> "a is equal to b"
}
코틀린에서 when문은 switch문과 달리 꼭 subject가 존재하지 않아도 됩니다.
따라서 복잡한 조건절을 가독성 좋게 코드를 작성하는 것으로 사용할 수 있습니다.
when (x) {
s.toInt() -> print("s encodes x")
else -> print("s does not encode x")
}
코틀린에서 조건절에는 변수, 상수뿐만이 아니라 메서드가 반환하는 값을 사용할 수 있습니다.
위 코드의 경우 x와 s.toInt()가 반환하는 값을 비교하는 것을 볼 수 있습니다.
Label
코틀린에서는 표현식에 @키워드를 사용한 label을 붙일 수가 있습니다.
beautifulLoop@ for (i in 1..100) {
// ...
}
위와 같이 for문에 beautifulLoop라는 label을 붙여주었습니다.
beautifulLoop@ for (i in 1..100) {
for (j in 1..100) {
if (i == 5) break@beautifulLoop
println("$i $j")
}
}
// 1 1
// 1 2
// ...
// 4 99
// 4 100
j가 사용되는 for문에서 break를 할 때 label을 명시하면 2중 for문임에도 불구하고 상위 for문 (i)가 종료됩니다.
이처럼 label을 사용하면 해당 label을 기준으로 break, continue, return이 동작됩니다.
fun main() {
beautifulLoop@ for (i in 1..100) {
for (j in 1..100) {
if (i == 5) continue@beautifulLoop
println("$i $j")
}
}
}
// 4 99
// 4 100
// 6 1
// 6 2
// ...
// 100 100
label을 사용한 continue로 i == 5인 경우 j for문을 건너뛸 수 있습니다.
fun loop(block: () -> Unit) {
block()
}
fun main() {
loop {
for (i in 1..5) {
if (i == 3) return // ❌ 컴파일 에러
println(i)
}
}
}
코틀린 lambda에서는 return을 사용할 수 없습니다. 따라서 위 코드에서도 loop에 전달되는 lambda 식 내부에서 return을 사용하면
컴파일 에러가 발생합니다.
fun loop(block: () -> Unit) {
block()
}
fun main() {
loop {
for (i in 1..5) {
if (i == 3) return@loop
println(i)
}
}
}
// 1
// 2
이러한 경우에는 lambda를 의미하는 @loop label을 return한다면 lambda 식을 탈출할 수 있습니다.
Exceptions
Exceptions help your code run more predictably, even when runtime errors occur that could disrupt program execution. Kotlin treats all exceptions as unchecked by default. Unchecked exceptions simplify the exception handling process: you can catch exceptions, but you don't need to explicitly handle or declare them.
예외를 사용하면 프로그램 실행을 방해할 수 있는 런타임 오류가 발생하는 경우에도 코드를 보다 예측 가능하게 실행할 수
있습니다. Kotlin은 기본적으로 모든 예외를 Unchecked Exception으로 처리합니다. Unchecked Exception은 예외 처리
프로세스를 간소화합니다. 예외를 잡을 수는 있지만 명시적으로 처리하거나 선언할 필요는 없습니다.
코틀린의 예외처리 try, catch, finally는 Java와 별차이가 없었지만 한 가지 큰 차이점이 있습니다.
공식문서에 따르면 코틀린은 모든 예외를 Unchecked exception으로 처리한다고 합니다. 따라서 Java에서는 필수적으로 try catch를
해줘야 했던 IOException 같은 예외를 코틀린에서는 필수적으로 처리해줄 필요가 없습니다.
'kotlin' 카테고리의 다른 글
코틀린 이모저모 - 5 (0) | 2025.04.23 |
---|---|
코틀린 이모저모 - 4 (0) | 2025.04.16 |
코틀린 이모저모 - 3 (0) | 2025.04.12 |
코틀린 이모저모 - 2 (0) | 2025.04.11 |