🚒

結局、例外処理は誰に任せればいいのか

2022/09/16に公開

はじめに読者のみなさまへ

【Java勉強したて、勉強しているしている最中のみなさまへ】
こんにちは!この記事の内容をみなさまの頭の隅に置いて頂けて役に立てる日が来れば嬉しいです!

【Javaには慣れてきたみなさまへ】
みなさまであれば、感覚的には理解できてる内容だと思います。ですが、自分の言語化できるということは、これからみなさまの助けになると思いますので、是非この記事を参考にしてみなさまなりに言語化してみてください!

【Java中級者のみなさまへ】
みなさまがJavaを教える立場になられた際に、見せる資料の一つとして採用されたら幸いです!この記事で間違っている箇所があれば指摘を頂けますと、さらに嬉しいです。

【Java上級者のみなさまへ】
お疲れ様です!私なりのアウトプットをしておりますが、間違ったことが書いてある場合はご指摘をお願い致します。

この記事のテーマ

この記事の主題は例外処理です。
Java言語でいうところのtry-catch文とスロー宣言(throws)の話です。

「これらの例外処理を誰にやらせるのが適切なのか?」

と私がJavaの例外処理を教える際に疑問に思ったことがきっかけでこの記事を書いています。

ここまでの説明では、まだ私が何の話をしたいのか掴みきれていない方が多いと思いますので、次章から例を交えながら詳しく説明します。

例外処理は伝播できるからこそ起こる疑問

前述の通り、例外処理にはtry-catch文スロー宣言(throws)があり、try-catch文では、例外が発生した際の処理をあらかじめ定めておくことができます。そして、スロー宣言はメソッド宣言時に行うことで、本来必要となるチェック例外を処理せずにメソッドの呼び出し元に例外処理を委ねることができます。

問題はスロー宣言のほうで、これを使うと例外処理を呼び出し元に任せることができますし、投げる回数に制約もないので、極論を言うととりあえず投げまくることも処理上はできます。

でも、とりあえず投げまくる処理なんてしてしまったら、結局はエントリーポイントまで到達してプログラム全体が止まってしまうので、普通はそんなやり方は無しですよね。

ということで、どんだけ例外処理を押し付けていいと言っても、誰かにやってもらう必要があります。

「で、誰が例外処理やればいいの?」

ある程度Javaに慣れている方であれば、別に適当にやればいいんじゃないの?と感じると思いますし、実際にちゃんとしてるという意味での適当なところで例外処理をしてくださでしょう。

でも、Java初学者にとっては適当がどこかも難しいですし、私はこれを聞かれたときには言語化できていませんでした、、、Java慣れしているみなさまでも言語化しろって言われたら言葉に詰まりませんか?

これを私なりに言語化した内容をお伝えすることが本記事の目的です。

さて、次章からみなさまと誰に例外処理させるべきなのかを考えていきます。

例外処理を誰にさせるのか

結論から言うと、

例外を発生させる原因となる処理を持つメソッドに例外処理を任せる

です。

当たり前のことを言ってるだけではと思われる方が多いかと思いますが、その通りです。当たり前のことを言っています。

ですが、このように言語化することでみなさまの判断の助けになることもきっとあります。

さて、当たり前のような言葉を使ってはいても抽象的な言葉なので、掴みどころがなくて分かりにくいと思いますので、ここから具体的な例を交えて、この結論がどう言う意味を示しているのか説明します。(本記事の例はスッキリわかるJava入門 第3版 (スッキリわかる入門シリーズ)を基にして作っています。良書ですので、是非どうぞ!)

まず、あなたはA社の社員だとしましょう。A社では、社長が経営方針を決め、あなたの上司である部長が具体的な施策を練ります。あなたは上司から開発を依頼させ、開発作業を開始しようとしますが、ある問題が発生してしまい開発不可能な状態になりました。

ここでは、あなたに発生したある問題がチェック例外として考えられます。そして、あなたが自分でこの問題を解決する場合がtry-catch文、部長に相談しに行く場合がスロー宣言であると考えることができますね。

さて、ここであなたに発生した問題は誰が解決するべきですか?お察しの方は正解です。発生した問題によって、誰が処理すべきか変わります。

例えば、開発不能になった原因が、あなたがパソコンを家に忘れてきたからだとしましょう。これを部長さんになんとかしてください!と言われても困ってしまいますよね。(相談することはよいことだと思います)

なので、ここではあなた自身が家に取りに帰るなどして、自力で解決するのがベターかなと思います。

これをJavaのメソッドに置き換えて考えます。あなたが開発メソッド(図の右側)のロジックを組み立てている際に、例外発生の原因となる処理が開発メソッド自身の中にある場合はtry-catch文で例外を捕まえてあげましょう。

ここまで来ると、スロー宣言の使い所も勘付かれている方も多いでしょう。スロー宣言は、例外が発生した箇所ではその例外を解決できない場合に使うのが良いと考えられます。

A社の例え話に戻りましょう。

あなたは、ある問題が発生して開発不能になっていましたね。その原因が開発に必要なソフトウェアのインストールが完了していないことだったとしましょう。そして、このソフトウェアのインストールには事前に部長の承認が必要です。

さて、この問題はあなただけで解決できるでしょうか?

多くの場合は、部長に承認をお願いしないと解決できませんよね。なので、あなたはここではこの問題の解決を委任するべきだと言えます。

Javaに置き換えると、開発メソッドで発生した例外の原因となる処理は開発メソッド内にはありません。そのため、開発メソッド内で例外処理をするのではなく、スロー宣言を行なって例外処理を呼び出し元である稼ぐメソッドに任せます。

そして、今回の例では稼ぐメソッドの中に例外の原因があったので、稼ぐメソッドでtry-catch文を書き、例外処理をします。

例外の発生が呼び出し元にある場合ってあるの?と感じる方もいらっしゃると思いますので、ここでも一つ例を挙げます。

JavaのFileReaderクラスが呼び出し元に例外の原因が発生する処理として挙げられます。このクラスはJavaでテキストファイルを読み込むことを可能としますが、呼び出し時に引数としてファイル名が必要です。

このファイル名が間違っていたら、呼び出されたFileReaderクラスではどうしようもないですよね。なので、FileReaderクラスのメソッドにはIOExceptionをスロー宣言しているものがあるのです。

最後に

ここまでの説明をして上記の結論を再喝します。

例外を発生させる原因となる処理を持つメソッドに例外処理を任せる

でしたね。本記事で例外処理の使い所をみなさまなりに言語化できたでしょうか。本記事がみなさまの中での言語化の助けになり、さらにみなさまの開発においてそれが役に立つことを祈っております。

この記事を終わる前に、下記の引用をご覧ください。

例外が発生する可能性があるメソッドでは、そのメソッドにおいて例外を捕捉するか、そのメソッドを呼び出したメソッドに例外を投げる(任せる)かを選ぶ必要があります(例外がRuntimeExceptionのサブクラスである場合を除く)。前者を選ぶ場合は「try-catch」構文を用い、後者を選ぶ場合は「throws」を用います。

このどちらを選択するかは、機械的には決められません。メソッドの役割を考えて選択する必要があります。

出典:throwsを用いるかどうかはメソッドの役割で決まる

「機械的に決められません」とありますが、私も正直これには同意しています。

え?例外処理を誰にやらせるか決めるための記事じゃないの?というのは当然の疑問ですが、この記事はあくまで私の考えを言語化してみなさまに共有させて頂いているものなので「こういう考え方があるんだな。使えそうな時に使お!」という認識でいて頂くのがベストです。

以上です。
ここまでお付き合い頂きありがとうございました!
ご感想・ご指摘を頂けると助かりますので、是非よろしくお願いします。

参考文献

Javaのtry-catch文で例外処理!finallyやthrowを使いこなそう
throws宣言を使いこなす!Java超初心者の勉強
Javaのエントリーポイントについて - Qiita
スッキリわかるJava入門 第3版 (スッキリわかる入門シリーズ)
【Java】FileReader、BufferedReaderでテキストファイルを読み込む
throwsを用いるかどうかはメソッドの役割で決まる

Discussion