例外
Kotlinでは、例外クラスはすべて「Throwable」クラスを継承しています。
例外クラスは必ずメッセージとスタックトレースを持っています。
また、任意で例外がスローされた原因についての情報も持つことができます。
例外をスローするためには、「throw」式を利用します。
また、「try-catch(-finally)」でスローされた例外をキャッチします。
fun main(args: Array) {
try {
checkArgs(100)
} catch (e: IllegalArgumentException) {
println("catch block.")
println(e.message)
println(e.stackTrace)
} finally {
println("finally block.")
}
}
fun checkArgs(num: Int) {
if (num > 10) {
throw IllegalArgumentException("num is too large.")
}
println("num is ${num}.")
}
catch block.
num is too large.
[Ljava.lang.StackTraceElement;@49476842
finally block.
catchブロックは何個あっても大丈夫です。
また、catchブロックやfinallyブロックは無くても構いませんが、catchブロックかfinallyブロックのいずれかは必要です。
また、tryは式ですので、if式やwhen式のように値を返します。
import kotlin.math.abs
fun main(args: Array) {
val num1 = checkNum(-5)
println("num1 is ${num1}")
val num2 = checkNum(-12)
println("num2 is ${num2}")
}
fun checkNum(num: Int) = try {
if (num < -10 || 10 < num) {
throw IllegalArgumentException("num is too large.")
}
abs(num)
} catch (e: IllegalArgumentException) {
println(e.message)
null
}
num1 is 5
num is too large.
num2 is null
チェック例外
結論から言うと、KotlinにはJavaのチェック例外に相当する機能はありません。
Kotlinの公式サイトでは、以下のJDKのインターフェースを例にして理由が挙げられています。
Appendable append(CharSequence csq) throws IOException;
このインターフェースはStringBuilderのインターフェースですが、「append」には「throws IOException」というチェック例外が設定されています。
つまり、プログラマはStringBuilderや、
このインターフェースを継承している何らかのlogやconsoleクラスに文字列を追加するたびに「IOException」をキャッチしなければいけません。
そうすると、いたるところに次のようなコードが埋め込まれることになります。
try {
log.append(message)
}
catch (IOException e) {
// 絶対に例外は発生しない
}
このような、例外をハンドリングしないキャッチブロックを作ることは、「Effective Java」などでも指摘されているように、お行儀がいいことではありません。
また、チェック例外については生産性の向上に寄与しないという批判的な意見も多いため、Kotlinでは採用していないようです。