Kotlin例外処理(try, catch, finally)

例外の基本

Kotlinの例外処理では、Javaと同じようにtrycatchfinallyキーワードを使用する。

次は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")

trycatchの場合、{}は省略できない。

次のようには書けない。

val num = try s.toInt() catch (e: NumberFormatException) null