Edit Page

例外(Exceptions)

Exceptionクラス

Kotlinのすべての例外クラスはThrowableクラスを継承しています。 すべてのexceptionはメッセージ、スタックトレース、そしてオプショナルですが理由(cause)を持ちます。

例外オブジェクトを投げるには、throw式を使います:

fun main() { //sampleStart throw Exception("Hi There!") //sampleEnd }

例外をcatchするには、trycatch式を使います:

try {
    // 適当なコード
} catch (e: SomeException) {
    // 例外ハンドラー
} finally {
    // finallyブロック(オプショナル)
}

catchブロックは一つもなかったり、もっとたくさんあっても良いです。 そしてfinallyブロックは省略しても良いです。 しかし、catchfinallyブロックのどちらか一つは最低でも必要です。

tryは式である

tryは式です。つまり、それは値を返す事が出来ます:

val a: Int? = try { input.toInt() } catch (e: NumberFormatException) { null }

try式の返す値はtryブロックの最後の式かcatchブロックの最後の値です。 finallyブロックの中身は式の結果となる値には影響を与えません。

Checked例外(検査例外)

Kotlinにはchecked例外(checked exception)はありません。 それにはたくさんの理由がありますが、どうして無いのかを示す簡単な例を挙げておきましょう。

以下は、JDK実装から持ってきたStringBuilderクラスのインターフェースです:

Appendable append(CharSequence csq) throws IOException;

このシグニチャは何か(何らかのStringBuilder、例えばログとかコンソールとか)に文字列を追加(append)する都度、 IOExceptionをcatchしなくてはいけない、と言っています。 なぜでしょう?それは実装によってはIOオペレーションを実行するかもしれないらです(WriterAppendableを実装しています)。 結果としてコードは、いたる所で以下のようになります:

try {
    log.append(message)
} catch (IOException e) {
    // 必ず問題無い
}

そしてこれは良くない事です。

Effective Java, 3rd Editionを見てみると、Item 77には、Exceptionを無視してはいけない(Don’t ignore exceptions)とあります。

Bruce Eckelはchecked例外についてこう述べています:

小さいプログラムを調査すると、例外仕様を要求するのは、開発者の生産性もコードの質も上がり得る、と結論出来ます。 ですが大規模なソフトウェアプロジェクトの経験は、違う結論を示唆しています。生産性は低下し、コードの質の向上もほとんどあるいは全く無い、というものです。

このトピックについてのさらなる考察を以下にリンクしておきます:

Java, Swift, Objective-CなどからKotlinのコードを呼ぶ時に呼び出し元に発生しうる例外を警告したければ、 @Throwsアノテーションを使う事が出来ます。 このアノテーションについては、JavaについてはこちらをSwiftとObjective-Cはこちらを参照ください。

Nothing型

throwはKotlinにおいては式です。だからそれを例えば、Elvis式などの一部として使えます:

val s = person.name ?: throw IllegalArgumentException("名前が必要です")

throw式はNothing型を持ちます。 この型は値を持たず、そこには絶対にコードが到達しない事を表します。 あなたのコードでも、決して戻ってこない関数にはNothingでその旨マークすることが出来ます:

fun fail(message: String): Nothing {
    throw IllegalArgumentException(message)
}

この関数を呼ぶ時は、コンパイラは実行はそのコードの続きに行く事は無いという事を認識出来ます:

val s = person.name ?: fail("名前が必要です")
println(s)     // この地点では 's' は初期化されていると分かっている

あなたはまた、型推論の所でもNothing型と遭遇する事があるかもしれません。 Nothing型のnullable版であるNothing?は、一つだけ可能な値があります。それはnullです。 あなたがもし推論される型の所でnullの値を用いて初期化し、他に何も型情報を推測する手がかりが無いケースでは、 コンパイラはこれをNothing?型だと推測します:

val x = null           // 'x' は`Nothing?`型
val l = listOf(null)   // 'l' は`List<Nothing?>型

Javaインターオペラビリティ

例外に関してのJavaとのインターオペラビリティの詳細については、Javaとのインターオペラビリティのページを参照ください。