코틀린에서 모든 예외 클래스는 Throwable 클래스를 상속받습니다.
예외 객체를 던지기 위해서는 throw식을 사용해야 합니다.
fun foo(arg: Int) {
if (arg > 5) throw Exception("arg $arg is too large")
// arg가 5보다 클 때, 예외를 던짐.
println(arg)
}
fun main() {
try {
foo(10)
} catch (e: Exception) {
println(e.message)
} finally {
println("end")
}
}
던져진 예외를 받기 위해서는, try-catch식을 사용해야 합니다. 캐치 블럭은 없을수도 있고, 여러개 존재할 수도 있습니다. finally 블럭은 생략될 수 있습니다. 하지만 catch 블럭이든 finally블럭이든 최소 하나는 존재해야 합니다.
try는 식입니다. 즉, try는 값을 반환할 수 있습니다.
try의 반환값은 try 블럭의 마지막에 적힌 값입니다. catch블럭도 마찬가지입니다. finally블럭은 값에 영향을 주지 않습니다.
fun foo(arg: Int) {
if (arg > 5) throw Exception("arg $arg is too large")
println(arg)
}
fun main() {
val result = try {
foo(10)
"success" // return value
} catch (e: Exception) {
println(e.message)
"fail" // return value
}
println(result) // fail
}
[출력]
arg 10 is too large
fail
함수에서 예외가 던져지면 예외가 처리되는 부분(catch)을 만날때 까지 스택 프레임을 거슬러 올라가면서 예외를 다시 던진다.
fun func2() {
throw IllegalStateException("func2 exception")
}
fun func1() {
func2() // rethrow to main
}
fun main() {
try {
func1()
} catch (e: Exception) {
println(e.message)
}
}
throw도 코틀린에서 식입니다. 따라서 아래와 같은 형태로 엘비스 식과 함께 사용될 수 있습니다.
fun printArg(arg: String?) {
arg ?: throw IllegalArgumentException("invalid arg")
println(arg.toInt())
}
throw식은 Nothing 타입을 가지고있습니다. Nothing 타입은 값을 가지고 있지 않으며 절대 도달할 수 없는 위치를 표시하는데 사용됩니다.
Nothing 타입은 함수가 절대 정상적으로 종료될 수 없는 상황에서 반환타입으로 사용됩니다.
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
Nothing 타입을 반환하는 함수가 호출 될 때, 컴파일러는 이 함수가 이후로 더 이상 실행되지 않는다는 사실을 파악합니다.
val s = person.name ?: fail("Name required")
println(s) // 's' is known to be initialized at this point
위의 예제는 타입 시스템에서 Nothing의 유용함을 잘 보여준다. 컴파일러는 Nothing을 반환하는 함수가 정상적으로 종료되지 않음을 알고 있다. 따라서 예제에서 컴파일러는 엘비스 연산자의 우항인 fail에서 예외가 발생한다는 사실을 파악하고 변수의 값이 널이 아님을 확인할 수 있다.
코틀린 공식 문서
드미트리 제메로프, 스메트라나 이사코바, 코틀린 인 액션(에이콘, 2017), 98, 282
Junyoung's Archives