Kotlinのcatchで例外の型ごとに適切に処理する方法を徹底解説!初心者でもわかるエラー対応の基本
生徒
「Kotlinのtry-catchって使い方はわかってきたんですが、catchの中でどうやってエラーの種類ごとに対応するんですか?」
先生
「いい質問ですね。Kotlinでは、catchに書く例外の型を指定することで、エラーの種類に応じた処理ができますよ。」
生徒
「えっ?エラーにも“種類”があるんですか?」
先生
「そうなんです。今回はそれぞれの型に合わせた処理方法をわかりやすく解説しますね!」
1. Kotlinの例外処理とcatchの基本
Kotlin(コトリン)では、例外(エラー)が発生したときにtry-catchを使ってプログラムを止めずに処理を続けることができます。たとえば、ユーザー入力の変換や計算など「失敗しやすい処理」を安全に扱えるのがポイントです。
エラー処理で重要なのがcatchブロックです。この中で何が起きたのかを確認し、メッセージを表示したり、代わりの値を返したりして、アプリが落ちないようにします。初心者のうちは「失敗しても落とさず、案内してあげる仕組み」と考えると理解しやすいです。
たとえば「文字を数字に変換する」場面では、数字以外が入力されるとエラーになりがちです。そこで、まずは次のようなシンプルな例で、tryとcatchの流れを体験してみましょう。
fun main() {
val input = "12a" // ここが数字なら成功、数字以外だと失敗しやすい
val number = try {
input.toInt()
} catch (e: Exception) {
println("数字として読み取れませんでした。入力を確認してください。")
0 // 失敗したときの代わりの値
}
println("読み取った数は $number です")
}
このサンプルでは、tryの中で変換を試して、うまくいかなかった場合だけcatchが動きます。こうしておくと、想定外の入力が来てもプログラムが途中で止まらず、次の処理に進めます。
2. catchでは例外の「型」を使い分ける
例外の型とは、「どんな種類のエラーが起きたのか」を表すラベルのようなものです。Kotlinではcatch(e: 型名)の形で書き、エラーの内容に合った対応を選べます。たとえば「数字にしたいのに文字が混ざっていた」「計算が成立しない」「nullを間違って使った」など、原因ごとにやるべき対処は変わります。
型を分けておくと、ユーザーに出すメッセージがわかりやすくなり、開発中の原因調査(デバッグ)もしやすくなります。まずは、よくある3つを押さえておきましょう。
NumberFormatException:文字を数字に変換できなかったとき(例:"12a"を数字にしたい)ArithmeticException:計算上のエラーが起きたとき(例:0で割ろうとした)NullPointerException:null(値がない状態)をうっかり使ったとき
例外の型を使い分ける感覚をつかむために、まずは「数字に変換できるかどうか」で処理を変える、いちばん簡単な例を見てみましょう。
fun main() {
val input = "abc" // 数字に見えるけど、実は文字だけ
val number = try {
input.toInt()
} catch (e: NumberFormatException) {
println("数字を入力してください(例:123)。")
0
}
println("number = $number")
}
このようにNumberFormatExceptionを指定しておくと、「数字に変換できなかった場合だけ」そのcatchが動きます。つまり、エラーの種類に合わせて“必要なときだけ”適切な案内や代替処理を入れられる、というのが型を使い分けるメリットです。
3. 複数のcatchで例外ごとに分けて処理する
次は、catchを複数書いて、例外(エラー)の種類ごとに処理を分ける方法です。ポイントは「起きたエラーにいちばん合うcatchが1つだけ選ばれて実行される」こと。つまり、同じ失敗でも原因に合わせてメッセージや戻り値を変えられるので、初心者でも動きが追いやすくなります。
下の例は、文字を数字に変換してから割り算をする流れです。入力が数字じゃなければ変換で失敗し、数字が0なら割り算で失敗します。どこで失敗しても落とさずに、結果を返すようにしています。
fun main() {
val input = "abc"
val result = try {
val number = input.toInt() // ここで数字にできないと失敗
10 / number // number が 0 だとここで失敗
} catch (e: NumberFormatException) {
println("入力値は数字ではありません。例:123 のように入力してください。")
-1
} catch (e: ArithmeticException) {
println("0で割ることはできません。別の数字を入力してください。")
-2
} catch (e: Exception) {
println("その他の予期しないエラーが発生しました。")
-999
}
println("結果は $result")
}
入力値は数字ではありません。
結果は -1
このときinputが"abc"なので、数字に変換できずNumberFormatExceptionが発生し、1つ目のcatchだけが実行されます。もしinputを"0"に変えると、今度は割り算で失敗してArithmeticException側に進みます。こうして「原因ごとに対応を分ける」のが、複数catchの基本です。
Kotlinを基礎からしっかり学びたい人や、 Java経験を活かしてモダンな言語にステップアップしたい人には、 定番の入門書がこちらです。
基礎からわかるKotlinをAmazonで見る※ Amazon広告リンク
4. Exceptionの順番に注意しよう
複数のcatchを書くときに、初心者がつまずきやすいのが例外の並び順です。Kotlinでは、上から順に「どのcatchに当てはまるか」をチェックし、最初に一致したものだけが実行されます。
Exceptionは、ほぼすべての例外をまとめた「大きな箱」のような存在です。そのため、これを先に書いてしまうと、後ろに書いた細かい例外が一切使われなくなります。必ず具体的な例外 → 広い例外の順で書くようにしましょう。
順番が大切だということを、次のシンプルな例で見てみます。
fun main() {
val input = "abc"
try {
input.toInt()
} catch (e: Exception) {
println("何らかのエラーが発生しました。")
} catch (e: NumberFormatException) {
println("数字に変換できません。")
}
}
この書き方では、実際に起きているのがNumberFormatExceptionでも、先に書かれたExceptionがすべて受け止めてしまいます。その結果、「数字に変換できません」という案内は表示されません。
正しくは、NumberFormatExceptionのような具体的な例外を先に書き、最後にExceptionを置くのが基本です。このルールを守るだけで、catchの動きがぐっと分かりやすくなります。
5. 実行結果で違いを体験してみよう
次に、割る数を"0"にしてみましょう。ArithmeticExceptionが発生するケースです。
fun main() {
val input = "0"
val result = try {
val number = input.toInt()
10 / number
} catch (e: NumberFormatException) {
println("数字に変換できません。")
-1
} catch (e: ArithmeticException) {
println("0で割ろうとしました。")
-2
} catch (e: Exception) {
println("その他の例外が発生しました。")
-999
}
println("計算結果は $result")
}
0で割ろうとしました。
計算結果は -2
6. catch内で例外の情報を表示する方法
もし原因を詳しく調べたい場合は、例外オブジェクトeの中にある情報を表示することもできます。
catch (e: Exception) {
println("エラー内容: ${e.message}")
-999
}
このように書くと、エラーの具体的なメッセージが表示され、デバッグ(エラーの原因を調べること)にも役立ちます。
7. よく使う例外の型一覧(初心者向け)
初心者のうちは、次の例外型を覚えておくと便利です:
- NumberFormatException:数字に変換できない
- ArithmeticException:数学的なエラー(0除算など)
- NullPointerException:nullを参照しようとした
- IllegalArgumentException:引数が不正
Kotlinは安全性を重視している言語なので、エラーが起きたときも落ち着いて処理できるよう、catchでしっかり対応しておきましょう。
まとめ
Kotlinのtry-catch構文は、初心者にとってシンプルに見えて実は奥が深いしくみであり、例外の型ごとに処理をわけることで安全性や可読性が大きく向上します。例外には複数の種類があり、発生するエラーの内容に応じて適切なcatchを用意することで、プログラムが突然停止するのを防ぎつつ、起きた問題を正確に把握し、その後の動作へつなげることができます。数字への変換に失敗したときに発生するNumberFormatExceptionや、0で割ったときに起きるArithmeticException、さらにnullを扱ってしまったときに発生するNullPointerExceptionなど、種類ごとに原因や性質が異なるため、catchの型指定を理解することはとても重要です。 また、複数のcatchブロックを書く場合には、型の順番に気をつける必要があります。より具体的な例外を先に書き、抽象的で広い範囲をカバーするException型は最後に書くことで、予期したとおりに処理が分岐し、すべての例外が正しく拾われるようになります。この順番を誤ると、特定の例外が意図したcatchに入らずにスキップされてしまうため、例外処理が曖昧になり、デバッグの手間も増えてしまいます。 また、catch内では例外オブジェクトからメッセージを取り出し、ログとして表示することで、エラーの特定が容易になり、原因を素早く把握することができます。特に開発段階ではe.messageで詳細を確認しながら、どの操作が誤っていたのかを理解すると、例外処理に対しての知識も深まります。そして、例外処理の理解が進むと、ユーザーに優しいメッセージを返したり、回復処理を行ったり、プログラムの挙動を整える力が身につきます。 Kotlin初心者は、まず「どんな例外が起きる可能性があるのか」を考えながらコードを書くことから始めると、自然とcatchの使い分けが上達していきます。tryブロックの中で何が起こりえるかを想像し、それに対応したcatchを用意することは、実践的なプログラミング力を鍛える良いトレーニングになります。例外に強いコードは、信頼性の高いアプリケーションを作るうえで欠かせない要素であり、今回学んだ型ごとの処理はその第一歩となるでしょう。
サンプルプログラム
以下は、複数の例外を適切にキャッチし、型ごとの動作を切り替える処理をまとめたコードです。具体的なエラーの種類に応じて返す値を変えたり、メッセージを表示したりすることで、例外処理の流れを確実に理解できます。
fun safeProcess(input: String): Int {
return try {
val number = input.toInt()
100 / number
} catch (e: NumberFormatException) {
println("数字に変換できませんでした。入力値: ${input}")
-10
} catch (e: ArithmeticException) {
println("0で割ることはできません。")
-20
} catch (e: Exception) {
println("予期しないエラーが発生しました: ${e.message}")
-999
}
}
fun main() {
val case1 = safeProcess("abc")
val case2 = safeProcess("0")
val case3 = safeProcess("5")
println("case1 の結果: $case1")
println("case2 の結果: $case2")
println("case3 の結果: $case3")
}
このプログラムでは、文字→数字変換の失敗、0除算、その他の例外という3パターンを確認できます。例外処理の基礎を理解するには、実際に動かしてみて挙動の違いを体験するのが一番です。
生徒
「catchの型によって処理を分けられるっていうのがすごく役に立ちました!数字じゃない入力と0除算って別々のエラーなんですね。」
先生
「そうなんです。同じ“エラー”でも原因が違えば対応も変わります。だから型ごとに処理を分けることが大切なんですよ。」
生徒
「Exceptionを最後に書く理由もわかりました!先に書いちゃうと全部そっちに吸い込まれちゃうんですね。」
先生
「その理解はとても重要です。順番を間違えると意図したcatchが動かないので注意が必要ですね。」
生徒
「例外のメッセージを表示して原因を知る方法も便利でした!自分でエラーを解決できる気がしてきました!」
先生
「エラーの理由がわかれば落ち着いて対処できますからね。今回の内容は実践でもよく使う知識なので、ぜひ覚えておきましょう。」
生徒
「はい!これからは型ごとにcatchを書くように意識してエラー処理を書いてみます!」