Kotlinで安全に例外処理を行うベストプラクティス【初心者向け解説】
生徒
「アプリを作ってるときに、途中で止まったり落ちたりすることがあるって聞いたんですけど、それってどうやって防ぐんですか?」
先生
「とても大事なポイントですね。プログラムの途中で予想外のエラーが起きると、アプリが止まってしまうことがあります。そのようなときに使うのが『例外処理』です。」
生徒
「Kotlinでは、どんなふうに例外処理をするんですか?初心者でもできる方法ってありますか?」
先生
「もちろんです!Kotlinには安全に例外処理を行うための書き方や便利な機能があります。今回はそのベストプラクティスを分かりやすく紹介していきますね。」
1. 例外(エラー)とは何かを理解しよう
プログラムを実行しているときには、自分では正しく書いたつもりでも、思いがけない問題が起きることがあります。たとえば、数字をゼロで割ろうとしてしまったり、読み込みたいファイルが実際には存在しなかったりする場面です。このように、正常な処理が続けられなくなる状況を「例外(れいがい)」と呼びます。
例外が発生すると、プログラムはその瞬間に止まってしまい、先へ進めなくなります。アプリが突然落ちる原因の多くは、この例外が適切に処理されていないことによるものです。そこで大切なのが「例外処理(れいがいしょり)」です。例外処理を行うことで、エラーが起きてもプログラムを安全に続けるための仕組みを作ることができます。
まずは、例外とはどんな状況なのかをイメージしやすくするために、初心者向けの簡単な例を見てみましょう。
fun main() {
val text = "100a"
println("この文字列を数字に変換します:$text")
// この処理は途中でエラー(例外)が発生します
val number = text.toInt()
println("変換結果:$number")
}
上の例では、いかにも数字に見える文字列ですが、実は「a」が混ざっているため数値に変換できず、プログラムはここで止まってしまいます。こうした予測しにくい問題が起きる可能性のある部分を理解し、適切に備えることが、Kotlinで安全にアプリを作るうえで大切な第一歩です。
2. try-catch文で例外をキャッチする
前の章で見たように、例外(エラー)が発生するとプログラムはその場で止まってしまいます。そこで登場するのが、Kotlinのtry-catch文です。tryの中に「エラーが起きるかもしれない処理」を書き、catchの中に「エラーが起きたときの対処」を書くことで、アプリが落ちるのを防ぎながら、安全に処理を続けることができます。
イメージとしては、「まずは普通にやってみる(try)→ダメだったらこう動く(catch)」という二段構えの動きです。プログラミング未経験の方は、tryは「とりあえずやってみる箱」、catchは「転んだときに受け止めるクッション」と考えると分かりやすいでしょう。
fun main() {
println("0で割り算をしてみます")
try {
val result = 10 / 0 // ここでエラー(例外)が発生する
println("計算結果:$result") // ここは実行されない
} catch (e: ArithmeticException) {
println("計算中にエラーが発生しました:${e.message}")
}
println("プログラムは最後まで実行されました")
}
このコードでは、わざと「10 ÷ 0」という間違った計算をしています。通常ならそこでプログラムが止まってしまいますが、tryの中でエラーが発生すると、Kotlinはすぐにcatchの中へ処理を移動させます。その結果、エラーメッセージを表示したあとでも、最後のprintlnまできちんと実行されます。このように、try-catch文を使うと、「エラーが起きても落ちないアプリ」をKotlinで実現しやすくなります。
実際のアプリ開発でも、「ユーザーの入力が想定と違う」「ネットワークの状態が悪い」など、いつエラーが起きるか分からない場面がたくさんあります。そうした「起きるかもしれない失敗」を、まずはtry-catchで受け止める、という考え方を身につけておくと、例外処理の基礎がぐっと理解しやすくなります。
3. 例外を限定的に扱う(catchは具体的に)
前の章では、try-catchを使うとプログラムが「落ちにくくなる」ことを見ました。ここでは、そのcatchの書き方をもう少し丁寧に見ていきます。catchでは、「どんな種類のエラーを捕まえるのか」を型で指定します。数値の変換に失敗したのか、ファイルが見つからなかったのかで、やるべき対処は変わってきますよね。そのため、catchはできるだけ具体的な例外クラスを書くのがKotlinの基本的な考え方です。
たとえば、次のようにざっくりと書いてしまうのは、初心者がやりがちなパターンです。
fun main() {
try {
val number = "abc".toInt()
} catch (e: Exception) {
// なんとなく全部ここで受け止めてしまう例
println("何かエラーが起きました")
}
}
catch (e: Exception)と書くと、「どんな例外でもとりあえずここで受け止める」という意味になります。一見すると便利そうですが、「結局なにが原因で失敗したのか」が分かりにくくなり、あとから不具合を調べるときにとても困ります。Kotlinで安全に例外処理を行いたいなら、「どのパターンの失敗なのか」を区別できるようにしておきましょう。
そこで、数値変換の失敗にはNumberFormatException、ファイル操作の失敗にはIOExceptionというように、具体的な型ごとにcatchを書くのがおすすめです。
import java.io.File
import java.io.IOException
fun main() {
try {
val text = "100a"
val number = text.toInt() // 数値変換に失敗するかもしれない
val file = File("data.txt")
val content = file.readText() // ファイル読み込みで失敗するかもしれない
println("変換結果:$number / ファイル内容:$content")
} catch (e: NumberFormatException) {
println("文字列を数値に変換できませんでした:${e.message}")
} catch (e: IOException) {
println("ファイルの読み込み中にエラーが発生しました:${e.message}")
}
}
このように、NumberFormatExceptionとIOExceptionを分けてcatchすることで、「入力の問題で失敗したのか」「ファイル操作で失敗したのか」がはっきり分かります。プログラムの振る舞いも、「入力をやり直してもらう」「別のファイルを案内する」など、状況に応じた案内がしやすくなります。Kotlinで例外処理を書くときは、なんとなく全部をひとまとめにせず、「どの種類のエラーをどう扱うのか」を意識して、catchを具体的に書く習慣をつけておきましょう。
Kotlinを基礎からしっかり学びたい人や、 Java経験を活かしてモダンな言語にステップアップしたい人には、 定番の入門書がこちらです。
基礎からわかるKotlinをAmazonで見る※ Amazon広告リンク
4. finallyブロックで後処理を行う
finallyブロックを使えば、例外の有無に関わらず必ず実行される処理を書くことができます。たとえば、ファイルやネットワークの接続を閉じる処理などが該当します。
fun main() {
try {
val data = "123a".toInt()
println("変換結果:$data")
} catch (e: NumberFormatException) {
println("数値に変換できませんでした")
} finally {
println("この処理は必ず実行されます")
}
}
5. runCatchingでスマートな例外処理
KotlinにはrunCatchingという便利な関数があります。これはtry-catchの簡易版で、エラーが起きても安全に処理できます。
fun main() {
val result = runCatching {
"abc".toInt()
}
result.onSuccess {
println("変換成功:$it")
}.onFailure {
println("エラー発生:${it.message}")
}
}
onSuccessとonFailureを使って、成功したか失敗したかを分けて処理できるので、初心者にもおすすめです。
6. 例外を無視しない、ログを残す
初心者がやってしまいがちなミスに、「catchの中を空にする」というものがあります。これは、エラーを見逃してしまう原因になります。
catch (e: Exception) {
// 何もしない ← NG!
}
エラー内容をきちんとログとして出力するようにしましょう。将来トラブルがあったときに原因を調べる手がかりになります。
7. 例外処理を使うときの心構え
例外処理は万能ではありません。なんでもかんでもtry-catchで囲めば良いというものではなく、「起こりうるエラーに対して備える」ことが目的です。
たとえば、ファイルの読み込みやユーザーの入力など、外部からの情報に頼る処理はエラーが起きやすいため、例外処理が必要です。一方、単純な計算や内部的な処理にまで過剰に使うのは避けましょう。
まとめ
Kotlinで安全に例外処理を行うためには、ただやみくもにtryやcatchを使うのではなく、例外の種類を理解し、状況に合わせて正しく扱うことが大切です。例外は突発的に発生するエラーであり、たとえばゼロで割る、変換できない文字列を数値へ変換する、存在しないファイルを開こうとするなど、思っているより多くの場面で発生します。アプリの開発では、ユーザーが予想外の操作をする場合もあるため、安全に処理を続けられる仕組みが必要です。そこでtry-catchを使えば、プログラムが途中で落ちることを防ぎ、ユーザーにとって優しい動作になります。 さらに、catchを書く時は、Exceptionでまとめて受けるよりも、NumberFormatExceptionやIOExceptionなど具体的な型で受けたほうが原因が見えやすくなります。開発中に発生したエラーを調査する場合でも、的確な例外が指定されていればすぐに修正へつながります。finallyでは、ファイルを閉じたり、ネットワークを切断したり、必ず実行したい後処理を書きます。これによって、例外が起きても安全に片付けができ、無駄なリソースを残さなくて済みます。 また、Kotlinらしい書き方として、runCatchingがあります。成功と失敗を直感的に分岐でき、コードがとても読みやすくなりました。開発経験が浅い段階でも扱いやすいので、try-catchよりスッキリ書きたい時に役立ちます。onSuccessとonFailureが用意されているため、「成功したらこうする、失敗したらこうする」という流れが自然に表現できます。 例外処理で特に気を付けたいのは、catchの中を空にしないことです。エラーが起きても何もしない処理は、あとから原因を調べられず、トラブルの発見が遅れます。ログを出す、ユーザーにメッセージを表示する、別の処理に切り替えるなど、何かしらの行動を残しておくことが大切です。Kotlinはログ出力も簡単なので、学習初期から意識しておくと役に立ちます。 さいごに、実用的なサンプルとして、ユーザー入力やファイル読み込みを含んだ例を用意しました。これらは実際のアプリ開発でよく使うので、手元でも動かして確認してみると理解が深まります。
実用例:ユーザー入力とファイル処理を安全に扱う
import java.io.File
fun main() {
println("数値を入力してください:")
val input = readLine()
val number = runCatching {
input!!.toInt()
}
number.onSuccess {
println("数値に変換できました:$it")
runCatching {
val file = File("sample.txt")
val text = file.readText()
println("ファイルの内容:$text")
}.onFailure {
println("ファイル読み込みに失敗しました:${it.message}")
}
}.onFailure {
println("正しい数値を入力してください:${it.message}")
}
}
ユーザーが入力した値をそのままtoIntすると失敗する場合がありますが、runCatchingを使えばアプリが止まらず、丁寧に処理を続けられます。ファイル操作も失敗しやすいため、必ずtry-catchやrunCatchingで包む習慣を持つと安心です。開発が進んでくると、例外処理があるかないかの違いが大きくなり、アプリの品質にも関係します。初心者のうちは面倒に感じるかもしれませんが、しっかり身につけておくと後で必ず役に立ちます。
複数の例外を分けて扱う例
fun main() {
try {
val data = "999a".toInt()
println(data)
} catch (e: NumberFormatException) {
println("数値に変換できませんでした")
} catch (e: NullPointerException) {
println("値がありませんでした")
} catch (e: Exception) {
println("予期しないエラーが発生しました:${e.message}")
} finally {
println("処理を終了します")
}
}
失敗の原因が違えば、ユーザーへの伝え方も変わります。数値変換の失敗と、値そのものが存在しない時では、伝えるメッセージがまったく違います。具体的なcatchを複数書くことで、より丁寧なエラー処理ができるようになります。実際のアプリでも、入力ミス・ネットワーク障害・ファイルアクセスなど、発生する問題はさまざまです。このように整理しておくことで、予測しやすく、修正もしやすくなります。
例外処理が役立つ場面はとても多い
スマホアプリ、Webサービス、ゲーム、家計簿、教育用システムなど、どのアプリでも例外が起きる可能性があります。ユーザーの入力、ネットワーク、データの保存、画像の読み込みなど、毎日のように失敗するきっかけがあるため、例外処理は欠かせません。正しい書き方を知っているだけで、アプリは安定して動作し、安心して使ってもらえるようになります。逆に例外処理が無いアプリは、すぐ落ちてしまったり、原因が分からず修正に時間がかかったりと、困る場面が増えてしまいます。 Kotlinはtry-catchやrunCatchingのおかげで、難しい知識がなくても安全なプログラムが書けます。これから学習を進める中で、データベース操作や外部APIとの通信などにも応用できるため、土台としてとても大切な考え方です。
生徒
「例外処理って難しいと思っていたけど、仕組みが分かったら怖くなく感じました。」
先生
「そうですね。失敗しそうな場所をあらかじめ囲っておけば、安心してアプリを動かせます。」
生徒
「runCatchingが便利でした!成功と失敗をきれいに分けられるのが分かりやすかったです。」
先生
「Kotlinらしい書き方なので、慣れてきたら積極的に使ってみてください。」
生徒
「catchの中を空にしない、具体的な型を指定する、finallyで片付ける、全部覚えます。」
先生
「それができれば、実践でも困らなくなります。次のステップではネットワークやファイル処理などに応用していきましょう。」