Kotlin 예외 처리 (try, catch, finally)
예외의 기본
Kotlin 예외 처리에는 Java와 동일하게 try
, catch
, finally
키워드를 사용한다.
다음은 NumberFormatException
예외를 처리하는 예이다.
try {
val num = "abc".toInt()
} catch (e : NumberFormatException) {
System.err.println(e)
}
Output:
java.lang.NumberFormatException: For input string: "abc"
예외를 던지는 것도 Java와 동일하게 throw
를 사용한다. 클래스의 인스턴스를 생성할 때 new
가 필요 없었던 것처럼, 여기에서도 new
는 필요 없다.
fun fibonacci(n: Int) {
if (n < 0) throw IllegalArgumentException("음수는 지정할 수 없습니다.")
// ...
}
Output:
java.lang.IllegalArgumentException: 음수는 지정할 수 없습니다.
예외 잡는건 필수가 아니다.
Java에서는 IOException
등 검사 예외(checked exception)를 던지는 메서드를 호출하는 함수는 반드시 catch
로 예외를 잡거나, 자신의 함수에서 throws IOException
을 선언해야 했다. Kotlin에서는 검사 예외(checked exception)와 비검사 예외(unchecked exception)를 구분하지 않으므로, 함수에 throws IOException
을 선언할 필요가 없다. 던져진 예외를 잡을지 말지는 호출자의 자유이다. 잡히지 않은 예외는 호출자의 함수에 전파된다.
fun throwIoException() {
throw IOException("로딩 에러!")
}
fun foo() {
// IOException을 던지는 함수를 호출하고 있지만,
// 이 foo 메서드에서는 throws 선언을 하지 않아도 된다.
throwIoException()
}
fun main() {
try {
foo()
} catch (e : IOException) {
System.err.println(e)
}
}
try를 식으로 사용할 수 있다.
Kotlin에서는 try
도 표현식이다. try
블록에서 결과 값을 그대로 변수로 받거나 함수의 반환값으로 반환할 수 있다.
아래 예에서는 try
블록에서 실행한 String.toInt()
의 결과를 num
변수에 대입하고 있다.
fun printIfInt(s: String) {
val num = try {
s.toInt()
} catch (e: NumberFormatException){
return
}
println(num)
}
Java에서는 try
블록 안에서 생성한 객체를 블록 밖에서 참조하려면 블록 밖에서 해당 변수를 정의해 두어야 했다(일단 null
값을 넣는 등). Kotlin에서는 그런 번거로운 작업을 하지 않아도 된다.
위 예제에서는 예외가 발생하면 return
으로 함수에서 바로 빠져나가도록 했지만, 삼항 연산자처럼 다른 값을 반환할 수도 있다. 다음 예제에서는 문자열을 제대로 구문 분석하지 못한 경우 num
변수에 null
을 저장하도록 하고 있다.
val num = try {
s.toInt()
} catch (e: NumberFormatException){
null
}
물론 이 예시와 같은 처리는 String.toIntOrNull
이라는 함수를 사용하는 것이 맞을 것이다.
val num = s.toIntOrNull(); // Int로 변환할 수 없는 경우 null로 변환한다.
추가로 if
식을 삼항 연산자적으로 사용할 경우, 분기 후의 식이 1개라면 아래와 같이 {}
를 생략할 수 있지만,
println(if (x == 0) "ZERO" else "NOT ZERO")
try
~ catch
인 경우 {}
는 생략할 수 없다.
아래와 같이 작성할 수는 없다.
val num = try s.toInt() catch (e: NumberFormatException) null