});2006年も折り返しを過ぎて、いよいよ暑いシーズンになってきました。昨年から「クールビズ」スタイルが導入されて、普段スーツで勤務しているエンジニアの方々にとってはだいぶ過ごしやすくなりましたね。普段はカジュアルで勤務しているエンジニアの方々にとっても、冷房が控えめになることで体調が良くなったりと恩恵があったのではないでしょうか。デバッグも「クールビズ」に倣って「クールに」こなせるようになるといいですね。今月もどうぞお付き合いください。「変数〜が初期化されていない可能性があります」が出てしまったら分類:コンパイルエラーこのコンパイルエラーは、メッセージの内容をそのまま読めば意味が理解できるものですので、原因は割合分かりやすい部類のエラーです。次の例を見てください。初期化されていない可能性があります。」というエラーが表示されます。初期化されていない可能性があります。確かに、7行目でsumというローカル変数を定義していますので、この変数が初期化されていないのが原因と思われます。Javaでは型の種類を問わず、あらゆる変数は値の代入を行って明示的に初期化しないと利用できない(ただ定義しただけでは、何も値が入っていないと見なされる)という文法になっています。言語によっては、定義しただけで、デフォルトの値が設定される場合もあるかもしれませんが、そのような言語を知っている型は注意が必要です。このプログラムではその後の11行目に「sum=0;」という記述がありますので、全く初期化していないわけでもなさそうです。してコンパイルエラーになってしまうのでしょうか。Javaのコンパイラは制御文(ifやswitch、forなど)を含めた構文解析をある程度行ってコンパイルエラーの判定をしています。このプログラムでは、sumを初期化する処理が、if文の条件式の評価結果がtrueの場合は実行されますが、評価結果がfalseの場合は実行されないため、「初期化されていない可能性がある」というコンパイルエラーと判定しているのです。このコンパイルエラーに対処するためには、制御文の実行結果がどのような結果になっても、必ず初期化処理が実行されるようにする必要があります。if文やswitch〜case文のような分岐を伴う制御処理の場合、どの条件にも当てはまらない場合の分岐を記述することができるようになっています。if文では、elseを使うことで、条件が成立しない場合の処理を記述できますし、switch〜case文では、default節を使うことによって、ほかのどの選択肢にも当てはまらない場合の処理を記述することができます。分岐処理の中で変数の初期化をする必要がある場合は、これらを考慮して初期化の処理が漏れないように注意してみましょう。例外処理を行うプログラムを書いていると、try節内で定義しておいた変数を、catch節内でも参照したいことが出てくると思います。これが顕著なのが、JDBCを使うプログラムを書く場合です。次のプログラムを見てください。APIを利用してテーブル内容の参照を行う処理を実装しています。finally節でResultSet、Statement、Connectionオブジェクトをクローズする処理を書いていますが、これはtry節中で例外が発生するかどうかにかかわらず、必ずこれらのリソースが解放されるようにするための記述です。ところがこのプログラムをコンパイルすると、「〜を解決できません。」というコンパイルエラーが複数発生します。注:J2SE5.0のjavacでコンパイルした場合は、「シンボルを見つけられません。「〜を解決できません。」というコンパイルエラーは、定義されていない変数を利用した場合などに表示されるエラーです。resultやstmt、connはtry節で定義してあるはずですが、なぜこのようなコンパイルエラーになってしまうのでしょうか。それには、Javaの変数のスコープ(有効範囲)を正しく知る必要があります。Javaにおける変数のスコープは、基本的に「ブロック」と呼ばれる「{」から「}」で囲まれた範囲で決定します。ブロックにはクラスの開始と終了を示すブロックから、メソッドの開始と終了を示すブロック、for文やif文などの制御文で使われるブロックまで、さまざまなレベルのものがありますが、スコープに関するルールはどのブロックでも共通です。同じメソッドの内部であっても、ブロックの内部で定義された変数は、そのブロック内でしか参照できません。ブロックの外側で定義されている変数であれば、そこに属するブロックであれば、どのブロックからでも参照することができます。変数のスコープこのプログラムの場合は、try節のブロック内部でresultやstmt、connを定義しているために、catch節やfinally節のブロックからは、直接その変数が参照できないためにコンパイルエラーになってしまうのです。try〜catch〜finally節はひとまとまりの構文ですから、変数は共通に使えるような気がしてしまいますが、try節、catch節、finally節はそれぞれ別のブロックとして認識されています。正しく動作させるためには、次のプログラムのように、これらの変数をブロックの外側で定義することになります。ちなみに、conn、stmt、resultの定義時にnullを代入しているのは、try節の内部で例外が発生した場合、finally節を実行する時点でこれらの変数が初期化されないままになっている可能性があるためです。「ClassNotFoundException」が発生したら分類:ランタイムエラーシステム開発をしていく中では、自分のマシンで動いたコードやモジュールが、別の環境に移して実行するとうまく動かない、ということがあります。原因は、もちろんその状況によって異なりますが、よく見られる原因の1つとして、モジュールの構成や環境設定などが、自分のマシンと同一になっていないことが挙げられます。「ClassNotFoundException」や別の項で紹介する「NoClassDefFoundError」「NoSuchMethodException」は、まさにそういった原因で発生します。アプリケーションが、クラスの文字列名を使用して次のメソッドでロードしようとしたが、指定された名前のクラスの定義が見つからなかった場合にスローされます。ここに説明されている3つのメソッドの中で、業務システム開発でよく使われると思われるのが、ClassクラスのforNameメソッドではないでしょうか。JDBCを利用するアプリケーションを開発する場合に、JDBCドライバのクラスをロードする場合にも利用しますし、共通のインターフェイスを実装した実装クラスのインスタンスを作成するためにそのクラスをロードするときなどにも利用することがあるでしょう。ClassクラスのforNameメソッドは、引数にパッケージ名を含むクラス名を指定し、そのクラスをロードします。「指定された名前のクラス定義が見つからなかった」というのは、(1)そのクラスのクラスファイルがCLASSPATHに登録された場所にない、もしくは(2)指定しているクラス名が間違っている、のどちらかのパターンです。Eclipseなどのツールを使って開発していて、Eclipse上で実行すれば例外が出ないのに、それをほかのマシンに持ってきて、コマンドラインなどで実行したらClassNotFoundExceptionが出た、という場合は、(1)のケースを調査してみましょう。そのクラスのクラスファイルがCLASSPATHに登録された場所にない、というのは、JARファイルのようなアーカイブに含まれているクラスをロードしようとしている場合に、そのJARファイルの場所がCLASSPATHに登録されていない場合も含みます。そもそも、開発環境上で開発、実行する段階から、この例外が発生している場合は、(1)(2)のどちらか、もしくは両方の可能性がありますので、両方のケースを調査し、CLASSPATHや指定しているクラス名が正しい状態になっているか確認してみましょう。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。