例外 try-catch-finally構文
☆ 例外
プログラムを設計する際は、実行時に想定外の事態が発生する可能性があることを考慮に入れておく必要がある
エラーを起こすことは絶対にダメ!
Javaのエラーは大きく分けると3種類
① 文法エラー(syntax error)
どこかの文法が間違っている
ex. セミコロンのつけ忘れ、変数名の間違い、クラス内部からしか呼び出せないprivateメソッドを外部から呼び出す
② 実行時エラー(runtime error)
プログラム実行中に突然動かなくなる
→実行中にエラーメッセージを表示して強制終了する
ex. 012と箱を用意した配列の3(用意している箱の範囲外)にアクセス
0で割り算、存在しないファイルを開く
③ 論理エラー(logic error)
実際に動かしてみると、プログラムの実行結果が想定していた内容と違う
エラーの原因 文法エラー
↓
気付く時 コンパイルするとエラーが発生して
失敗する
↓
対処 コンパイラが指摘したコードの箇所を修正する
エラーの原因 実行時エラー
↓
気付く時 実行すると途中で強制終了する
↓
対処 あらかじめ「エラーが発生した時の対応策」を記述しておく
エラーの原因 論理エラー
↓
気付く時 実行すると想定外の処理結果になる
↓
対処 原因箇所を自力で探してコード修正
②の実行時エラー
「プログラム実行中に想定外の事態が発生したこと」
想定外の事態…例外的状況/例外
ex. ・パソコンのメモリが足りなくなった
開発用はOKだったが、動作中に足りなくなった
・存在すべきファイルが見つからない
誤ってファイルを削除してしまったなど
・nullが入っている変数のメソッドを呼び出した
想定外操作で本来入るはずのない値(nullなど)が入った
⇨共通 プログラマが開発する時点では、想定外の事態(例外的状況)を予防できない
:
例外的状況に備えて対策を準備し、その状況に陥った際にその対策を実施する
→例外処理
〈例外的状況の対策をするための構文〉
try{本来の処理
}catch(IOException e){
//例外発生時に実行される文
System.out.println("エラー終了");
System.exit(1);
} ←例外を起こした際に、エラーが起こったということを知らせる表示の出力とその操作から脱出させるための処理
tryとcatchというブロックを使用(try-catch文)
通常実行されるのは、tryブロックの中の処理だけ。
catchブロックの中身は例外状況が発生した事を検知すると、
tryブロックの中で行われていた処理がcatchブロックの中に移行する
(そのため、catchブロックの中に「例外的な状況が発生したときに実行される処理」を記述しなければならない)
・例外の種類
1. Error
回復見込みがないから
catchしてもしょうがない
ex.OutOfMemoryError(メモリ不足)
classFormatError(クラスファイルが壊れている)
2.Exception
回復見込みがある状況
①Exception系例外
(java.lang.Exceptionの子孫の中からRuntimeExceptionの子孫を除いたもの)
その発生を十分に想定して対応を考える必要がある例外的状況を表すクラス
☆回復見込みがありので、catchすべき
ex.IOException(ファイルの読み書きができない)
ConnectException(ネットワークに接続できない)
②RuntimeException系例外
(java.lang.RuntimeExceptionのクラスの子孫)
必ずしも常に発生を想定すべきとまではいえない例外的状況
(いちいち処理してるとキリがない)
☆try-catch文を使うかは任意
ex.NullPointerException(変数がnull)
ArrayIndexOutOfBoundsException(配列の添字が不足)
この中で重要なのは①Exception系例外!
(なぜなら、対処すれば回復するから)
↓
JavaではException系例外が発生しそうな命令を呼び出す場合、
try-catch文を用いて「例外が発生した時の代替処理」を用意しておかないと
コンパイルエラーになる
ex. import java.io*: //FileWriterクラスが所属するパッケージ名
//FileWriterのコンストラクタはIOExceptionを発生する可能性がある
public class Main{
public static void main(String[ ] args){
try{FileWriter fw=new FileWriter("data.txt");
}catch(IOException e){
System.out.println("エラーが発生しました");
System.exit(1);
}
}
try-catch文を記述するためには、
「どのメソッドを呼び出したらどのような例外を発生させる可能性があるか」を
事前に知っておく必要がある
→APIリファレンスに掲載されているものを参考にする
ex.FileWriter
FileWriterのインスタンス生成時にコンストラクタを呼び出す時は
IOExceptionをキャッチする
↓
try-catch文が必要になるという解釈
public FileWriter(String fileName) throws IOException
//引数リストの後に「throws 例外クラス名」を表記
}catch(IOException e){
//例外状況の詳細が変数eに代入される
→この情報を取り出してエラーの状況を把握する
System.out.println("エラー:"+e.getMessage( ));
System.exit(1); //途中で処理から脱出
}
・String getMessage( )….例外的情報の解説文を表示する
・void print StackTrace( )…スタックトレースの内容を画面に出力する
スタックトレースとは?
「JVMがプログラムのメソッドをどのような状態で呼び出し、どこで例外が発生したか」という経緯が記録された情報
(実行時エラーが発生したときのエラー画面と内容は一緒)
☆ さまざまなcatch構文
(基本) try{
本来の処理
}catch(例外クラス 変数名e/ex){
例外が発生した場合の処理
}
・2種類以上の例外をキャッチする
ex. try{ …
}catch(IOException e){
System.out.println("ファイルの書き込みが失敗したときの例外処理");
System.exit(1);
}catch(NullPointerException e){
System.out.println("nullだけだった時の例外処理");
System.exit(2);
}
・例外をザックリ処理する(多態性を使う)
try{
本来の処理
}catch(抽象的な例外クラス 変数名){
例外が発生した場合の処理
}
例外クラスの継承を考えれば、
IOExceptionもNullPointerExceptionもざっくり捉えれば、どちらもException
ex. try{ ….
}catch(Exception e){ ←Exception系の子孫ならどれでもキャッチする
System.out.println("何らかの例外が発生");
}
※ ただこれだとおおざっぱな例外処理になる
☆ fw.close( )のようなファイルを閉じる処理の前に
もし例外が起こってしまい強制終了してしまったら、大変なことになる
(ファイル開けっ放し)
→close( )メソッドのような後片付け処理はどんな時でも必ず実行されないといけない
⇩ そこで….
・try-catch-finally構文 finally→どんな時でも必ず実行される
try{
本来の処理
}catch(例外クラス 変数名){
例外が発生した場合の処理
}finally{
例外があってもなくても必ず実行する処理
}
ファイルを閉じる、開いたデータベースやネットワークの接続を閉じるなどの
「後片付け処理」
→必ずfinally処理を使う