Javaの例外は「その場で処理」か「相手にスロー」の2種類で処理しよう

例外処理とはアプリケーションを実行した際に生じるエラーのことで、Javaでは例外の発生に対処する処理を行うことが必須とされています。

私達初学者はプログラムのメインの実装に手一杯で例外処理について考える余裕を持ちづらいですが、例外処理を行わないとコンパイルエラーとなってしまうため対処の方法を一緒に学びましょう。

例外処理を行うのは「回避できない例外」

例外といっても大きく2つのタイプに分けることができます。

1つ目は回避可能な例外、いわゆるバグと呼ばれるものです。メソッドの呼び出し時に呼び出し先が存在しない、また配列のサイズを超えてアクセスするなどの事象が該当します。

これらは開発者の責任で発生を未然に防ぐ必要のあるもので例外処理の対象とはなりません。

一方で未然に回避できない問題もあります。主にユーザーのアクションが起点となって生じるようなエラーです。例えば割り算の割る数に0を入力したり、アクセスしようとしたファイルが存在していないなどの事象が該当します。

ユーザー起点の例外

例外処理では開発者の責任で生じるエラーではないものの、問題が発生する可能性がある処理を行う際に処理を中断させないために開発者が事前に対処を施します。

例外処理の基本はtry…catch

では具体的にどのように例外を処理するかというと、try…catch命令を用いて処理を行います。

tryブロックではアプリケーション本来の処理を記述し、catchブロックで例外が発生した場合の処理を記述します。catchブロックのカッコには発生する例外の種類(クラス)が入り、例外の種類に応じた処理が可能です。

try{
  アプリケーションのメインの処理(例外発生の可能性がある)
}catch(例外1 変数1){
  //例外1が発生したときの処理
  System.out,println("ファイルがみつかりません");
}catch(例外2 変数1){
  例外2が発生したときの処理
}
:

例外が発生することをスロー(throw)、そして発生した例外を受け取る(処理する)ことをキャッチ(catch)といいます。

例外が発生する可能性のある処理はAPIリファレンスを見る

では例外が発生する可能性がある処理をどのように判断するかというと、それはAPIリファレンスに書いてあります。各メソッドに起こりうる例外が記載されているため、記載がある例外に対しては処理を行う必要があります。

Java APIリファレンス

Eclipseで開発をしている場合は例外処理が必要な箇所を自動で通知してくれます。(例外が処理されないとコンパイルエラーとなるため)

Eclipseの例外

例外処理は「その場で処理」か「スローする」かの2種類

ここからは具体的な例外処理の方法を2種類に分けて考えます。

1つ目は例外が発生した場所で処理を行う方法で、もう一つは呼び出し元に処理をスローする方法です。

その場で例外処理を行う

その場で例外処理をする場合は処理が中断しないような処置を行います。

例えば文字フォーマットに例外が発生した場合は空文字として処理するなどが挙げられます。このような回復処理は場合によって異なります。

その他によく行われる処理はエラーメッセージやログを出力する方法です。以下の3つの全ての例外インスタンスが持つメソッドとしてよく例外処理に用いられます。

メソッド処理内容
String getMessage()エラーメッセージを取得
Throwable getCause()エラー原因を取得
void printStackTrace()スタックトレースを出力

ここで例外処理を行うcatchブロックを空白にすること(例外の握りつぶし)は避けるべき点に注意しましょう。空白でも動作はしますが、バグの発生時に問題の特定を難しくするため何らかの処理は行うようにしましょう。

例外をスローして呼び出し元に任せる

プログラムによっては例外が発生した場所では手に負えない場合もあります。

例えばファイルの読み込みの場合を考えると、例外が発生するのはファイルを読み込むメソッド内ですが例外処理をその場で処理するのは難しいです。

先程も述べたようにプログラムによって回復処理が異なるため、例外処理はメソッドの呼び出し元で処理されるべきです。Javaではthrow句を使うことで例外を呼び出し元にスローして例外処理を任せることができます。

throw句による例外処理

throw句を使った処理は例えば次のように書くことができます。

public static void example() throws FileNotFoundException {
  throw FileNotFoundException("Invalid file path");
}

例外をスローする際にはメソッドにおいてthrows句で発生する可能性のある命令を宣言する必要があります。throws句で宣言されたメソッドが呼び出される際は、呼び出し元に宣言された例外に対して例外処理を強制します。

例外をスローする際の注意点

例外をスローする際には以下の2点に注意しましょう。

Exceptionでスローしない

Exceptionは全ての例外クラスの元となっているため、どんな例外も網羅できる反面具体的な例外処理ができないデメリットがあります。より具体的な例外に対して詳細な例外処理をしましょう。

回復可能な例外をスローする

例外をスローする目的は処理を中断させないために呼び出し元に何らかの回復処理を施してもらうためです。そのためスローする例外は回復可能な例外に限るべきです。

回復不能な例外をスローしてもただ例外処理の手間を増やすだけで意味を成さないため気をつけましょう。

スローによく用いられる例外クラスは以下の6つです。

例外内容
NullPointerEcceptionオブジェクトがnull
IndexOutOfBoundsException配列のインデックスが範囲外
UnsupportedOperationException要求された操作が未サポート
(例:固定長配列にaddメソッドを使う)
IllegalArgumentExceptionメソッドに渡された引数に問題がある
ArithmeticException計算で例外的な条件が発生
(0で割る)
NumberForamtException数値の形式が正しくない

コメント

タイトルとURLをコピーしました