第12回 エラーに対処するプログラムを書く
平井玄
2004/1/8
| 予期しないエラーに対処するには? |
プログラムのエラーには文法エラーのようにコンパイル時に発見できるものと、0で割り算してしまうような、コンパイル時には発見できないものがあります。あるいは、ハードディスクが故障してデータをファイルに書き込めないなど、実行時にはプログラマが想定できないようなエラーも発生します。
このような想定外の場合に備えて、エラー発生時の処理を決めておくのが「例外」という機能です。まずは簡単な例を示しますので、どのような動作になるかを確認してみましょう。
| 10÷Nを計算する その1 |
import java.io.*; |
この実行結果は以下のとおりです。
C:\>javac DivideCalc.java |
一見正しくコンパイルできそうなプログラムでしたがエラーになってしまいました。なぜこのプログラムがコンパイルできなかったのか考えてみましょう。
本連載で初めて登場するクラス「BufferedReader」はバッファからデータを取り出すために使うクラスです。コンストラクタの引数でnew
InputStreamReader(System.in)と指定することにより、読み込み元のバッファを「InputStreamReader」からと指定しています。InputStreamReaderはバイト単位のデータを文字として読み込むためのクラスです。この場合、バイト単位のデータの読み込み元を「System.in」に指定しています。これまでのサンプルプログラムで何度となく登場していた「System.out」が画面出力を表すのに対して、System.inはキーボードからの入力を表します。従って「BufferedReader
r = new BufferedReader( new InputStreamReader(System.in) )」全体では「キーボードから入力したバイト単位のデータを文字として読み込んでバッファにためるためのオブジェクトを生成し、そのオブジェクトにBufferedReader型の変数rでアクセスできるようにする」という意味になります。
コンパイラがエラーを検出したのは「s = r.readLine();」の部分です。BufferedReaderクラスのメソッドであるreadLine()を実行するときに、「IOException」という例外が発生する可能性があるのに対処されていませんよ、というエラーです。readLine()のように、メソッドによっては発生し得る特定の例外についてプログラマが対処方法を決めておかなければならないのです。このとき使うのが「try〜catch」のブロックです。
| 10÷Nを計算する その2 |
public class DivideCalc2 { |
今回は無事にコンパイルできたはずです。「String s = r.readLine();」の部分でキーボードから文字を入力し、リターンキーを押したところで文字列が変数sに格納されます。さらに、変数sに格納された文字列はInteger型の静的メソッドであるparseInt()によって数値に変換され、int型の変数nに格納される、という流れです。parseInt()はHTMLDocument型クラスでHTMLを解釈するときに作ったparse()と同じように、文字列を解釈するメソッドです。
では、プログラムを実行してみましょう。
C:\>javac DivideCalc2.java |
変更後のプログラムでは、処理の大部分を「try { 〜 }」のブロックに入れました。さらに、「catch { 〜 }」ブロックで、tryブロック内で発生したIOExceptionの例外を捕捉し、エラーメッセージを表示するようにしました。try〜catchの構文では、tryブロックに本来の処理、catchブロックに例外発生時の処理を書くことで、予期しないエラーに対処できるようになります。
ただ、このプログラムは発生し得る例外に対処し切れていません。例えば、キーボードから数字ではない文字を入力したらどうなるでしょうか? 試しに「abc」という文字列を入力してみましょう。
C:\>java DivideCalc2 |
数値に変換できるはずのない「abc」という文字を入力したため、「int n = Integer.parseInt(s);」の部分で例外が発生してしまいました。実は、tryブロック内の処理で発生した例外を正しく捕捉するには、適切なcatchブロックを個々に記述しなければならないのです。
ここでJava言語のAPI 仕様でIntegerクラスのparseInt()メソッドで発生する例外を調べると、文字列が構文解析可能な整数型を含まない場合に「NumberFormatException」という例外が発生することが分かります。そこで、プログラムを以下のように修正します。
| 10÷Nを計算する その3 |
public class DivideCalc2 { |
このプログラムを実行し、Nの値に「abc」を入力してみましょう。
C:\>java DivideCalc3 |
今回はエラーが表示されずにプログラム内で例外が捕捉されて、ユーザーには対処方法のメッセージが表示されました。「catch ( <捕捉したい例外のクラス>
<変数名> )」と記述することで、例外ごとに対処方法を切り分けられるのです。
一方、例外を捕捉できさえすればよい、という場合もあるでしょう。発生し得るすべての例外をいちいち調べていたらきりがありません。そこで、例外の種類を特定しない以下のようなcatchブロックの書き方もできます。
| 10÷Nを計算する その4 |
public class DivideCalc4 { |
| 例外発生の有無に関係なく実行するための −finallyブロック− |
catchブロックは例外を捕捉し、例外発生時の処理を記述するために使いますが、例外が発生してもしなくても処理しなければならないことはどうしたらいいのでしょうか?
例えば、テキストファイルの内容を画面に表示するプログラムを考えてみます。WindowsなどのOSが管理しているファイルを読み込むには、まず特定のファイルを扱うことをOSに対して宣言(オープン)し、その後、使い終わったことをOSに通知(クローズ)しなければなりません。ディスクの読み込み中にエラーが発生し例外を捕捉しても、そのままプログラムを終了させてしまうのではなく、必ずファイルを閉じなければならないのです。
このように、特定のリソースの利用開始から終了するまでに起こる例外を捕捉しつつ、最後に確実にリソースを解放することは、ユーザーに安定したサービスを提供するプログラムを書くために欠かせないことです。そこでfinallyという文を使います。
| テキストファイルを表示する |
import java.io.*; |
tryブロックの中にtryブロックがある、一見複雑な構造になりました。そこで重要な部分を抜き出して説明します。
FileInputStream fis = new FileInputStream(args[0]); |
1行目では、テキストファイル読み込み用のクラスFileInputStreamのオブジェクトを生成しています。FileInputStreamクラスのコンストラクタの引数になっている「args[0]」は、コマンドラインでこのプログラムを実行したときの1番目の引数を格納する配列です。例えば、「java ShowTextFile TEST.TXT」と入力したときのargs[0]には「TEST.TXT」が格納されます。
C:\>javac ShowTextFile.java
|
| 制御文としての役割 |
例として挙げたテキストファイルを読み込んで表示するプログラムの主要部分は、3つの部分に分かれています。tryブロックでは、データを1文字ずつ読み込んで、ファイルの終わりに達するまで画面に表示します。catchブロックではIOExceptionの例外を捕捉し、ディスクI/Oエラーによる読み込みの中断に備えています。最後のfinallyブロックでは、現在開いているファイルを閉じています。
この例で重要なのは、最後のfinallyブロックはたとえ例外が発生しても必ず実行されることです。例えば、ディスクI/Oエラーが発生してcatchブロックに制御が移ったとします。このときプログラムが画面に「ディスクI/Oエラー」と表示することまでは通常の文と同じです。しかし、次にあるreturn文が実行されてメソッドを終了するとき、すぐにはメソッドを抜け出さずにfinallyブロックにある「fis.close()」が実行されるのです。「第6回 プログラムの制御構造を理解する」でreturnを「メソッドを呼び出した親メソッドに制御を戻す」文と説明しました。しかし、try〜catch〜finallyの場合は実行順が通常とは少し異なり、finallyブロックにある文を実行してから親メソッドに制御が戻されます。つまり、例外処理はreturnやbreakといった処理を中断させる制御文のふるまいを若干変える効果があるのです。
また、この例ではファイルをオープンして内容を表示するのに関連する処理が、本来の処理、エラー時の処理、終了処理の3つに区分けされました。例外を使うと、forやwhileなどの制御文とは別の意味で、プログラムの構造を役割に応じて記述できるのです。そこで次回は、プログラムを分かりやすく記述するという例外のもう1つの側面について説明します。
いまから始めるJava バックナンバー
- 第1回 Java2 SDKで学習の準備
- 第2回 Javaの変数の本質を知る
- 第3回 クラスを簡単に理解しよう
- 第4回 クラスの継承の本質を知る
- 第5回 メソッドとコンストラクタはなぜ必要?
- 第6回 Javaプログラムの制御構造を理解する
- 第7回 Javaの制御文を使いこなそう
- 第8回 メソッドの挙動を変えるオーバーライド
- 第9回 クラスのメンバに利用制限を付与するアクセス制御
- 第10回 Javaのクラスをグループ化するパッケージ
- 第11回 Javaのクラスの理解を深める
- 第12回 Javaプログラミングにおけるエラー対処
- 第13回 Javaの例外をスマートに記述する
- 最終回 Javaの抽象クラスとインターフェイス
| 「いまから始めるJava」記事一覧 |
ホワイトペーパー(TechTargetジャパン)
- Android NDKでJNIを使用してアプリを高速化するには (2010/3/17)
C/C++やOpenGL ESといったネイティブコードを使うためのNDKとJNIを紹介し、その使い方や注意点を徹底解説します - 調査の難しい「OutOfMemoryError」事例、5選 (2010/3/11)
Java開発者が避けて通れないメモリ不足エラーの基本的な問題切り分け方法と発生につながる事例、対処法を解説 - 究極の問題解析ツール、逆コンパイラJD-Eclipseとは (2010/3/8)
ライブラリ内で例外が発生! そのクラスのソースコードを調べたい!! 自動で逆コンパイルしてくれる無料Eclipseプラグインがあります - いまさら聞けない「Webサービス」の常識 (2010/2/26)
昨今では企業システムでも使われる「Webサービス」の概念やJava標準のJAX-WSを紹介しJBoss WSでサンプルを作成
|
|
スキルアップ/キャリアアップ(JOB@IT)
スポンサーからのお知らせ
- - PR -
| 「いつかは壊れるサーバ」そんな故障に 迅速で安価に手軽に対応する方法とは? New! |
| 「特権ユーザー」の事件を防げ! 万能権限を持つユーザーの管理方法とは? New! |
| 仮想環境の構築とデータ保護の特効薬?! 実績と信頼性の高いパッケージで安心運用 |
| 仮想環境のバックアップもこれまでどおり 「まるごと取ってまるごと戻す」簡単運用 |
| おばかアプリ選手権、第4弾開催中!! ムダにカッコよくてくだらない作品求ム! |
| 社内ファイルサーバを“クラウド”に統合 VPN直結「クラウド型ストレージ」を紹介 |
| その数、なんと400台以上! グループ内 サーバの「統合管理」によるメリットは? |
| 美人!? まあまあ? 気になる いやし系!! PV急増で「美人時計」がとった手段とは? |
| 進化を続ける富士通ストレージETERNUS DX 製品開発者の自信を裏付けるものとは何か |
| 運用管理の課題を“2つの観点”から分析 ユーザー満足度の高い「仮想環境」とは? |
- - PR -
お勧め求人情報

**先週の人気講座ランキング**
〜CCNA編〜
| ◆ | TomcatやJBossなどAPサーバ環境に関する 情報を集約! “業務”用APサーバ大百科 New! |
| ◆ | 一気に解説! 最新のクラスタストレージ 「RAIDを超えたストレージ基準」……など New! |
| ◆ | クラウド的ユーザー体験の変化は脅威か? 仮想化技術を使いこなす運用管理術を紹介 New! |

| ◆ | 上司や部下、部署内メンバーとの情報共有 を“ガラッ”と変えるコラボツールとは? New! |
| ◆ | おばかアプリ選手権、第4弾開催中!! ムダにカッコよくてくだらない作品求ム! |
| ◆ | 社内ファイルサーバを“クラウド”に統合 VPN直結「クラウド型ストレージ」を紹介 |

| ◆ | Twitterのアカウントはなぜ突破された? メールによる新手の攻撃手法とその対策 |
| ◆ | もう仮想化のお試しフェイズは終わりだ! Hyper-V 2.0が基幹システムも仮想化 |
| ◆ | 美人!? まあまあ? 気になる いやし系!! PV急増で「美人時計」がとった手段とは? |

| ◆ | クライアント企業から求められる人材 ⇒IT技術と経営戦略を併せ持つ「戦略家」 |
| ◆ | .NET編集長が実践する「技術情報検索術」 サンプル・コードを簡単に探す“技”は? |
| ◆ | 業務効率と情報セキュリティ対策を両立! 手間なく確実に機密情報を守る方法とは? |

| ◆ | 進化を続ける富士通ストレージETERNUS DX 製品開発者の自信を裏付けるものとは何か |
| ◆ | 運用管理の課題を“2つの観点”から分析 ユーザー満足度の高い「仮想環境」とは? |

| ◆ | 【CTC事例】約30の基幹システムを統合! 膨大なバッジジョブを制御した方法は? |
| ◆ | 仮想化すればコストは削減できるか? 仮想化に必要な「3つの視点」を解説する |
| ◆ | その数、なんと400台以上! グループ内 サーバの「統合管理」によるメリットは? |






