1. 概要

このチュートリアルでは、Kotlinでの例外処理について説明します。

2. 例外

例外は、プログラムの実行中に発生し、従来のフローを混乱させる問題です。 これは、無効な算術演算、nullオブジェクトへの参照などのさまざまな理由で発生する可能性があります。

例外処理は、このような問題を適切に処理し、プログラムの実行を継続するための手法です。

3. Kotlinの例外

Kotlinでは、プログラムの実行時実行中にスローされる未チェックの例外のみがあります。 すべての例外クラスは、クラスThrowableの子孫です。 Kotlinはthrowキーワードを使用して例外オブジェクトをスローします。

KotlinはJavaから例外の概念を継承していますが、Javaのようなチェックされた例外をサポートしていません。

チェックされた例外は、Javaで物議を醸す機能と見なされます。 コード品質をさらに向上させることなく、開発者の生産性を低下させます。 他の問題の中でも、チェックされた例外はボイラープレートコード、ラムダ式の使用中の困難にもつながります。

そのため、他の多くの最新のプログラミング言語と同様に、Kotlin開発者も言語機能としてチェックされた例外を含めることに反対しました。

4. トライキャッチブロック

Kotlinでの例外処理には、try-catchブロックを使用できます。 特に、例外をスローできるコードは、tryブロック内に配置されます。 さらに、対応するcatchブロックが例外の処理に使用されます。

実際のところ、tryブロックの後には常にcatchまたはfinallyブロック、あるいはその両方が続きます

try-catchブロックを見てみましょう。

try {
    val message = "Welcome to Kotlin Tutorials"
    message.toInt()
} catch (exception: NumberFormatException) {
    // ...
}

4.1. 式としてのTry-Catchブロック

式は、別の値を提供するために実行される1つ以上の値、変数、演算子、および関数の組み合わせである場合があります。 したがって、Kotlinの式としてtry-catchブロックを使用できます。

さらに、 try-catch 式の戻り値は、tryまたはcatchブロックの最後の式です。 例外が発生した場合は、catchブロックの値が返されます。 ただし、式の結果はfinallyブロックの影響を受けません。

try-catchを式として使用する方法は次のとおりです。

val number = try {
    val message = "Welcome to Kotlin Tutorials"
    message.toInt()
} catch (exception: NumberFormatException) {
    // ...
}
return number

4.2. 複数のキャッチブロック

Kotlinのtryブロックと一緒に複数のcatchブロックを使用できます。 特に、 try ブロックでさまざまな種類の操作を実行する場合、これが必要になることがよくあります。これにより、複数の例外がキャッチされる可能性が高くなります。

さらに、すべてのキャッチブロックを最も具体的な例外から最も一般的な例外の順に並べる必要があります。 例として、ArithmeticExceptioncatchブロックは、Exceptioncatchブロックの前に置く必要があります。

複数のcatchブロックを使用する方法を見てみましょう。

try {
    val result = 25 / 0
    result
} catch (exception: NumberFormatException) {
    // ...
} catch (exception: ArithmeticException) {
    // ...
} catch (exception: Exception) {
    // ...
}

4.3. ネストされたトライキャッチブロック

ネストされたtry-catchブロックを使用して、別のtryブロック内にtry-catchブロックを実装できます。 たとえば、これは、コードのブロックが例外をスローする可能性があり、そのコードのブロック内で別のステートメントがさらに例外をスローする可能性がある場合に必要になる可能性があります。

ネストされたtry-catchブロックを使用する方法を見てみましょう。

try {
    val firstNumber = 50 / 2 * 0
    try {
        val secondNumber = 100 / firstNumber
        secondNumber
    } catch (exception: ArithmeticException) {
        // ...
    }
} catch (exception: NumberFormatException) {
    // ...
}

5. 最後にブロック

finallyブロックを使用して、例外が処理されるかどうかに関係なく、常にコードを実行できます。 また、 catch ブロックを省略することで、finallyブロックをtryブロックと一緒に使用できます。

finallyブロックを見てみましょう。

try {
    val message = "Welcome to Kotlin Tutorials"
    message.toInt()
} catch (exception: NumberFormatException) {
    // ...
} finally {
    // ...
}

6. キーワードを投げる

Kotlinでthrowキーワードを使用して、特定の例外またはカスタム例外をスローできます

Kotlinでthrowキーワードを使用する方法は次のとおりです。

val message = "Welcome to Kotlin Tutorials"
if (message.length > 10) throw IllegalArgumentException("String is invalid")
else return message.length

Kotlinの式としてthrowを使用することもできます。 たとえば、Elvis式の一部として使用できます。

val message: String? = null
return message?.length ?: throw IllegalArgumentException("String is null")

throw式はタイプNothingの値を返します。 この特殊なタイプには値がなく、到達不能コードブロックを示すために使用されます。 さらに、関数で Nothing タイプを使用して、常に例外をスローすることを示すこともできます。

fun abstractException(message: String): Nothing {
    throw RuntimeException(message)
}

7. 注釈をスローします

@Throwsアノテーションを使用して、KotlinとJava間の相互運用性を提供できます。 Kotlinは例外をチェックしていないため、スローされた例外を宣言しません。 Kotlinで関数を定義しましょう:

fun readFile(): String? {
    val filePath = null
    return filePath ?: throw IOException("File path is invalid")
}

これで、JavaからKotlin関数を呼び出して、例外をキャッチできます。 Javaでtry-catchを作成する方法は次のとおりです。

try {
    readFile();
}
catch (IOException e) {
    // ...
}

Kotlin関数が例外を宣言しなかったため、Javaコンパイラはエラーメッセージを表示します。 このような場合、Kotlinで@Throwsアノテーションを使用してエラーを処理できます。

@Throws(IOException::class)
fun readFile(): String? {
    val filePath = null
    return filePath ?: throw IOException("File path is invalid")
}

8. 結論

このチュートリアルでは、Kotlinでの例外処理のさまざまな方法について説明しました。

いつものように、これらの例のコードはGitHubから入手できます。

Kotlinの機能の詳細については、Kotlinチュートリアルのいずれかをご覧ください。