Javaに関する様々な情報をご紹介します。

2実行時のエラー

Javaに関する様々な情報をご紹介します。

実行時のエラー

エラーメッセージの見方

以下のエラーメッセージを例に取り説明します。このエラーメッセージはスタックトレースと呼ばれるもので、エラーの原因を解明するのに役立ちます。

C:\Java\source\TEST>java ExMsg  [1]
Exception in thread "main" java.lang.NullPointerException  [2]
     at ExShow.showMsg(ExShow.java:3)  [3]
     at ExMsg.main(ExMsg.java:5)  [4]
  1. (1)プログラムExMsgを実行
  2. (2)java.lang.NullPointerExceptionという例外が発生
  3. (3)ExShowクラスのshowMsgメソッド内で発生。発生箇所はExShow.javaファイルの3行目。
  4. (4)[3]はExMsgクラスのmainメソッド内から呼び出し。呼び出し箇所はExMsg.javaファイルの5行目。

java.lang.NullPointerExceptionという例外が、atで示される箇所で発生していることを表します。atは下から呼び出された順に記載されており、一番上のものが直接例外に関係している箇所です。そのため、上から順にソースを見ながら、エラーの原因を解明していきます。

まず、APIリファレンスや検索エンジンなどで例外の意味、解決のヒントなどを確認します。そして、atで示される箇所のソースを見ながら、エラー原因を解明していきます。
※例外を検索する際、例外の後に:で区切られ、メッセージが表示される場合があります。そのメッセージも含めて検索すると、有効な解決のヒントが得られる場合があります。

java.lang.NoClassDefFoundError

必要なクラスが見つからない場合に発生する例外です。必要なクラスは例外の後に表示されます(java.lang.NoClassDefFoundError:○○○ の場合、○○○が必要なクラスです。)。主な原因として、以下のようなものがあります。

  • ファイル名は間違っていませんか。大文字小文字も区別されます。
  • コマンドラインで実行する際、○○○.classと拡張子も指定して実行していませんか。実行する際は、.classは必要ありません。
  • クラスパスは正しく設定されていますか。
    ※.クラスパスに.(カレントディレクトリ)は指定されていますか。
    ※.必要なクラスファイル、jarファイルがクラスパスに指定されていますか。
    ※.Tomcatの場合、必要なjarファイルがWEB-INF/libディレクトリに設置されていますか。
  • クラスファイル、jarファイルの権限(読取可能)は正しく設定されていますか。

QuickTimeはインストール時、環境変数CLASSPATHを設定します。古いバージョンのQuickTimeはその際、CLASSPATHに.(カレントディレクトリ)を設定しないようです。これにより、java.lang.NoClassDefFoundErrorが発生する事例があります。

java.lang.NoSuchMethodError

必要なメソッドが見つからない場合に発生する例外です。必要なメソッドは例外の後に表示されます(java.lang.NoSuchMethodError:○○○ の場合、○○○が必要なメソッドです。)。主な原因として、以下のようなものがあります。

  • 「java.lang.NoSuchMethodError: main」と表示された場合は、有効なmainメソッドが見つからなかったことを表します。
    ※.実行時に指定するクラスファイルには、必ずmainメソッドが必要です。
    ※.mainメソッドは「public static void main(String[] args)」という形式で記載する必要があります。
  • jarファイルのバージョンは最新のものですか。古いバージョンのjarファイルを利用していると、新しく追加されたメソッドが利用できないということがあります。

java.lang.NullPointerException

オブジェクトの値がnullの時に、そのオブジェクトのメンバ変数やメソッドを参照したときに発生する例外です。
まず、ソースコードのどの位置で例外が発生しているかを確認し、発生している箇所のオブジェクトがNullでないかを確認します。確認は、発生している箇所のオブジェクトをSystem.out.printlnなどで出力して調べます。

//str1はnullであるためlengthメソッド実行時にNullPointerExceptionが発生します
String str1 = null;
System.out.println(str1.length());

java.lang.ArrayIndexOutOfBoundsException

不正なインデックスを使って配列がアクセスされたときに発生する例外です。インデックスが負の値の場合、インデックスが配列のサイズ以上の場合に発生します。スタックトレースを見て、どの箇所で例外が発生しているか確認します。例外が発生している箇所の配列のインデックスが不正な値でないか確認します。

  • 配列のインデックスの初期値は0です。配列を「int[] array = new int[10]」で生成した場合は、インデックスは0~9です。
  • for文やwhile文で一定の条件の際にインデックスが不正な値になり、例外が発生しているケースが見られるようです。
int[] array = new int[10];
//インデックスが負の値のため、例外が発生します。
System.out.println(array[-1]);
//インデックスが配列のサイズ以上のため、例外が発生します。
System.out.println(array[10]);

java.lang.NumberFormatException

文字列を数値型に変換しようとした時に、文字列の形式が適切でない場合に発生する例外です。主に以下のような場合に発生します。

  • 文字列が数値に判別できない形式(アルファベット、ひらがななど)であった場合。
  • 文字列が空白であったり、nullであった場合。
  • 文字列に小数点があり、変更先の数値型がintなどの整数型であった場合。
  • 文字列の範囲が、変更先の数値型の範囲を超えていた場合。
//文字列が数値に判別できない形式のため、例外が発生します。
String str1 = new String("aiueo");
int int1 = Integer.parseInt(str1);

//文字列がnullであるため、例外が発生します。
String str2 = null;
int int2 = Integer.parseInt(str2);

//変更先がint型であるが、文字列に小数点があるため、例外が発生します。
String str3 = new String("3.14");
int int3 = Integer.parseInt(str3);

//文字列の値の範囲が、変更先のint型の範囲を超えているため、例外が発生します。
String str4 = new String("10000000000");
int int4 = Integer.parseInt(str4);

java.lang.UnsupportedClassVersionError

コンパイル時と、実行時のJavaのバージョンが異なる場合に発生する例外です。 各環境のバージョンを確認してみてください。「javacの確認方法:javac -J-version」、「javaの確認方法:java -version」。
バージョンが異なっている原因としては、環境変数PATHへの設定値が誤っている場合に起こっているようです。デフォルトの設定のままだと、OSに標準でインストールされているJava環境が実行され(%SystemRoot%\system32が先に実行される)、コンパイル時のJava環境と異なるケースが見られるようです。対処策としては、以下のような方法があります。

  • ユーザー環境変数のPATHに設定している場合は、システム環境変数のPATHに設定しなおす。
  • システム環境変数のPATHに設定する際、先頭に設定する(%SystemRoot%\system32の前)。

開発環境の理由から、意図的にコンパイル時と実行時のJavaのバージョンが異なっている場合は、コンパイル時に-targetオプション、-sourceオプションを指定することで、実行時の環境に合わせたコンパイルを行うことができます。

java.lang.ArithmeticException

不適切な算術計算が行われた場合に発生する例外です。具体的には、0で除算した時に発生します。解決策としては、0で除算が行われないように除算する前に値をチェックするか、0で除算が行われたときに備えてtry ~ catch文で例外処理を記述する必要があります。

java.lang.OutOfMemoryError

JavaVMのメモリ構造は大きくヒープ領域と、スタック領域に分かれています。ヒープ領域には、インスタンス化されたオブジェクトの情報、メソッドの定義情報などが格納されています。OutOfMemoryErrorはこのヒープ領域が不足したときに発生する例外です。発生する要因としてはプログラムのコーディングミス、根本的にヒープ領域が足りない場合の2つに大別されます。

【プログラムのコーディングミスの場合の注意点】

  • 無限ループになっている箇所はないか。
  • closeメソッドが必要な箇所で呼び出されているか。
  • 大量のデータを読み込んでいないか。
  • sessionスコープ、applicationスコープのデータを多用していないか。必要な箇所でのみ利用しているか。

【根本的にヒープ領域が足りない場合の対処方法】

  • 動作させるアプリケーションの要件、どうしても大量のデータを読み込む必要があるなど、根本的にヒープ領域が足りない場合は、実行時に「-Xms」オプション、「-Xmx」オプションを付与することでヒープ領域を拡大することができます。
    「-Xms」オプションは初期割当て領域を指定する際に使用します。
    「-Xmx」オプションは最大割当て領域を指定する際に使用します。
Xms、Xmxオプションをそれぞれ128MBに指定して、Testプログラムを実行
C:\Java\source\TEST>java -Xms128m -Xmx128m Test

※Tomcat実行時のヒープサイズを指定する場合は、環境変数CATALINA_OPTSで指定します。各アプリケーション実行時のヒープサイズを指定する場合は、そのアプリケーションのマニュアルを参照してください。多くの場合、設定方法が用意されています。

java.lang.StackOverflowError

JavaVMのメモリ構造は大きくヒープ領域と、スタック領域に分かれています。スタック領域には、ローカル変数の情報などが格納されています。StackOverflowErrorはこのスタック領域が不足したときに発生する例外です。発生する要因としてはプログラムのコーディングミスであることが多いようです。無限ループになっている箇所がないか確認しましょう。
スタック領域も、実行時に「-Xss」オプションを付与することで領域を拡大することができます。

2実行時のエラー