[???] /
[Java FAQ] / [S003]
S003: 問題解決の一歩
[S003 Q-01]
エラーが出るのですが、どうしたらよいですか?
[S003-A01]
どのようなエラーが出たかによって、対処方法が異なります。
(1) java.lang.NoClassDefFoundErrorが出るとき
・ Exception in thread "main" java.lang.NoClassDefFoundError: Hogehoge/class
と出るとき
このメッセージが表示された場合、
java Hogehoge.class[リターン]
のように実行していませんか?
java Hogehoge[リターン]
と実行してみてください。
java コマンドを実行するときには、ファイル末尾の ".class"は不要です。
javaインタープリタ起動コマンドに与えるのは「クラス名」のみです。
・ Exception in thread "main" java.lang.NoClassDefFoundError: Hogehog
と出るとき
一つ前のメッセージに良く似ていますが、よく見ると末尾が "Hogehog"
となっていて、最後の "e"が抜けています。
java Hogehog[リターン]
と実行してないでしょうか。
java Hogehoge[リターン]
と実行してみてください。
(2) Exception in thread "main" java.lang.NoSuchMethodError: main
と出るとき
このメッセージが表示されるのは、実行時に指定したクラスの中に
mainメソッドが含まれていないときです。
mainメソッドを含んでいるクラスを指定してください。
もし、指定したクラスに mainメソッドが含まれているのならば、
ソースファイル(.javaファイル)の中身を確認します。確認する場所は、
mainメソッドの定義部分です。
public static void main(String[] args)
もしくは
public static void main(String args[])
のような形になっているでしょうか。
※ argsは別の名前でもかまいません
"static"というキーワードが抜けていたり、"String[] args"や
"String args[]"を "String args"となっていないでしょうか。
(3) Failed to load Main-Class manifest attribute from
hogehoge.jar
と出るとき
java -jar hogehoge.jar
と実行しようとしていませんか?
-jarオプションを使うときには jarファイルに格納されている
MANIFESTファイルに mainメソッドを含むクラスを指定しておかなければ
なりません。この記述方法は「Java プラットフォーム V1.2での拡張機能と
アプリケーションのサポート」(JDK ドキュメンテーションに附属)
http://java.sun.com/products/jdk/1.2/ja/docs/ja/guide/extensions/spec.html
の「-jarオプション」を参照してください。
(4) 処理の途中で次のようなメッセージが出るとき
Exception occurred during event dispatching:
...
このときは[S003-02: 実行時エラーの読みかた]を参照してください。
(5) 処理の途中で
Exception in thread "main" java.lang.NoClassDefFoundError: Foobar
at Hogehoge.main(Hogehoge.java, Compiled Code)
のようなメッセージが出るとき
Hogehogeクラスから Foobarクラスを呼びだそうとしましたが、
Foobarクラスが読み出せなかったときに上のようなメッセージが出ます。
考えられる原因とその対処は次のとおりです。
a) Foobar.class を誤って消してしまっていた(もしくは名前が変っていた)
Foobar.java が存在するときは、Foobar.java を javacで
コンパイルしてください。
Foobar.java が存在しないときは、
class Foobar...
と、どこかに記述されているソースファイルを見つけて、
javac でコンパイルしてください。
b) Foobar.class は存在するが読み取り権限がなかった
Foobar.class に読み取り権限を与えてください。
[S003 Q-02]
実行時にエラーが出力されたのですが、どのように見ればいいのでしょうか?
[S003 A-02]
Javaでは実行時にエラーが発生すると、次のような出力を行ないます。
[出力例(左端の"数値:"は行番号を示すためのもので、実際には表示されません)]
1: Exception occurred during event dispatching:
2: java.lang.NullPointerException
3: at sun.awt.motif.X11Graphics.drawImage(X11Graphics.java:587)
4: at UnresolvedPeerApplet.paint(UnresolvedPeerApplet.java:7)
5: at sun.awt.motif.MComponentPeer.handleEvent(MComponentPeer.java:246)
6: at java.awt.Component.dispatchEventImpl(Component.java:2429)
7: at java.awt.Container.dispatchEventImpl(Container.java:1032)
8: at java.awt.Component.dispatchEvent(Component.java:2289)
9: at java.awt.EventQueue.dispatchEvent(EventQueue.java:258)
10: at java.awt.EventDispatchThread.run(EventDispatchThread.java:68)
これは、あるスレッドの実行時に例外が発生したことを意味しています。この
メッセージは「スタックトレース」と呼ばれるもので、あるスレッドについて
メソッドがどのように連鎖して呼びだされているかを現わしています。この
メッセージは次のように読みとります。
・(1行目) 例外が発生
・(2行目) 具体的な例外名: java.lang.NullPointerException
・(3行目) sun.awt.motif.X11Graphicsクラスの drawImageメソッド(ソース
ファイル X11Graphics.java、行番号 587)で例外発生
・(4行目) UnresolvedPeerAppletクラスの paintメソッド(ソースファイル
UnresolvedPeerApplet.java、行番号 7)を実行中に例外を検知
・...
・(10行目) java.awt.EventDispatchThreadクラスの runメソッド(ソース
ファイル EventDispatchThread.java、行番号 68)を実行中に
例外を検知
・最終行に出ているクラス(java.awt.EventDispathThread)とメソッド名(run)に
よって、このスレッドは開始された
(1) もし、スタックトレースの先頭の行(3行目)のクラスが自分で作ったクラス
であるのならば、例外が発生した行がどうなっているのかを、ソース
ファイルを見て確認します。
この例で挙げてある NullPointerExceptionの場合、[S003-03]に挙げた方法を
用いて調べてください。
(2) もし、スタックトレースの先頭の行(3行目)のクラスが自分で作ったクラス
ではないのならば、[S003-04]を参照してください。
[S003 Q-03]
NullPointerExceptionと表示されてしまいました。どうすればいいのでしょうか?
[S003 A-03]
NullPointerExceptionがスタックトレースに表示された場合、
(1) スタックトレースに記述されているソースの行番号をまず調べてください。
(2) もしその行が
obj.foo(...);
のようにメソッド呼出しとなっていたならば、変数 obj の値が nullでは
ないかと推測できます。
System.out.println(obj);
obj.foo(...);
と、直前に printlnを挿入して、再度実行してみてください。
例外出力の直前に obj の値が出力されているはずです。
(3) スタックトレースの先頭が自分で作成しているクラスではない場合は、
メソッドの引数に nullが与えられているかもしれません。
この解決方法は[S003-4]を参照してください。
[S003 Q-04]
例外が発生したときのスタックトレースの先頭が自分のクラスではありません。
どのように調べれば良いのでしょうか
[S003 A-04]
スタックトレースの先頭に表示されるクラスが自分で作成したものではない場合、
スタックトレースの最も上の行にある自分が作ったクラスを探し、行番号で示さ
れている行を、ソースファイルでまず確認します。
(1)メソッド呼び出しになっている場合
メソッドの引数に問題があります。
APIリファレンスを参照して、該当する例外が発生するかを確認してください。
もし発生した例外が NullPointerException である場合は、その引数のどれかに
nullが入っています。引数にある変数に nullが入っていないか
System.out.printlnメソッドを使って調べてください。System.out.println
メソッドの引数に変数名を入れることで、変数の値を確認することができます。
(2)配列操作(及びそれに類すること)を行っている場合
恐らく IndexOutOfBoundsException のサブクラスが例外として発生している
ものと思われます。配列が範囲外となっていないかを確認してください。
[S003 Q-05]
スタックトレースに行番号が表示されないので、デバッグができません。
どのようにデバッグすればいいのでしょうか
[S003 A-05]
考えられる原因と対処方法は次のとおりです。
1. コンパイル済のクラスファイル中に、ソースファイル行番号の対応表が
含まれていない。
コンパイル時に最適化オプション( -O )が指定されている場合に起きます。
対処>>
最適化無しで再コンパイルしてください。
javac ソースファイル名...
2. 実行時に JIT(Just In Time)コンパイラを使用している
実行時にJITコンパイラを使用していると、スタックトレースに出力されて
いるソースファイル名と行番号の部分が (Compiled Code) となってしまう
場合があります。
対処>>
JITコンパイラを使用しないで再実行してください。
プロンプト> java -Djava.compiler=NONE クラス
JDK 1.1では、デバッグ用のコマンドも使えます。
プロンプト> java_g クラス
[S003 Q-06]
スタックトレースの出力が長すぎて上の方が見えません。
なにか対処はあるでしょうか。
[S003 A-06]
1. プロンプト> java -Djava.pipe.output=true クラス
とすると、標準エラー出力に出ていたものが標準出力で出力されます。
これをリダイレクトすることで、エラーの内容が把握できます。
2. 自作プログラムの場合は、main()メソッドの先頭で
System.setErr(System.out);
とすることで、1. と同様の効果が得られます。
3. プログラムの main()メソッドを呼びだすプログラムを作ります。
その際に 2. の手法を用いると、例外を補足できます。
ただし、例外全てが java.lang.reflect.InvocationTargetException
になってしまいます。JDK 1.2では、この他にも本来の例外の情報が
表示されますが、JDK 1.1.xでは InvocationTargetExceptionのみ表示されます。
[[サンプル]]
import java.lang.reflect.*;
class java2 {
public static void main(String[] args) throws Exception {
System.setErr(System.out);
Class clazz = Class.forName(args[0]);
String args2[] = new String[args.length - 1];
for(int i = 0; i < args2.length; i++) {
args2[i] = args[i + 1];
}
Method mainMethod =
clazz.getMethod("main", new Class[] {String[].class});
mainMethod.invoke(null, new Object[] {args2});
}
}
4. bash, tcshといった UNIX由来のシェルプログラムの Windows版を入手して
エラー出力もリダイレクトさせてください。
[S003 Q-07]
javac でのコンパイルエラーが多すぎて上のほうが読めません
なにか対処はあるでしょうか。
[S003 A-07]
次のような方法があります
1. javacのオプションである -J-Djavac.pipe.output=true を使って、
エラーを標準出力に出力されるようにします。そうすることで、
リダイレクトを使用することができます。
例)
javac -J-Djavac.pipe.output=true HelloWorld.java > error.log
J2SE SDK 1.3.0 では javac から上記の機能が省かれていますので、
javacの代わりに oldjavac を使用してください。
例)
oldjavac -J-Djavac.pipe.output=true HelloWorld.java > error.log
J2SE 1.2.0 では -Xstdout を使うことも出来ます。この機能が使えるか
どうかを確認するには javac -X とすると -X を使用したときのオプション
内容が表示されます。
例)
javac -Xstdout HelloWorld.java > error.log
2. 標準エラー出力をリダイレクトできるシェルを使ってください。
例)
[sh系のシェルの場合]
javac HelloWorld.java 2> error.log
[csh系のシェルの場合]
(javac HelloWorld.java > dummy) >& error.log
この場合, dummy に標準出力, error.log に標準エラー出力が
リダイレクトされます
[S003 Q-08]
変数の値がリセットされたりして、おかしいのです。
どこをどう見ればいいでしょうか。
[S003 A-08]
System.out.println(変数名);
を各所に散りばめて、変数の値をチェックしていきましょう。
また、jdb や、Java 開発ツールのデバッガを使って、実行時の変数の値の変化を
追っていき、おかしくなる箇所を見つけて対処しましょう。
[S003 Q-09]
サーバに置いたアプレットが上手く動作しません。どうして動かないのでしょうか?
[S003 A-09]
考えられる原因は幾つかあります。
1. .classファイルを FTPで転送するときに ASCIIモードで転送してませんか?
.classファイルは BINARYモードで転送してください。
2. .classファイルのファイル属性が読み込み不可になってませんか?
.classファイルだけでなく、その.classファイルを転送した先が
WWWサーバから見えるようになっていますか?
もし、そのような状態になっているならば、読み込み可能な状態にしてください。
3. HTMLファイルで指定された位置に .classファイルが存在していますか?
.classファイルは HTMLファイルで指定した場所に置いてください。
例えば、
HTMLファイル中に
<APPLET CODE=HelloWorldApplet.class WIDTH=160 HEIGHT=120>
と設定していたならば、 .classファイルは HTMLファイルと
同じディレクトリに置いてください。
[S003 Q-10]
Applet ... could not be loaded と言われて実行できません。
[S003 A-10]
Webサーバのアクセスログを見て、AppletViewerがクラスファイルを
ロードする URLを確認することができます。その場所にクラスファイルを
置いたかどうかを確認してください。
Webサーバのアクセスログを参照できない場合も、クラスファイルが
指定した場所に置かれているかを確認してください。
[S003 Q-11]
アプレットでの System.out.println(...) の出力先はどこを見ればいいのですか?
[S003 A-11]
appletviewerを起動したコンソールや Java対応のブラウザから起動した
Javaコンソールに System.out.println(...)の内容が表示されます。
ブラウザの Javaコンソールを使用しようとしても、標準ではこの
Javaコンソールは表示されません。Javaコンソールを表示するには、
ブラウザ上の設定が必要です。
Netscape Navigatorの場合)
ブラウザのメニューにある[Communicator]
--[Java Console]
Microsoft Internet Explorerの場合)
ブラウザのメニューにある[表示]
--[インターネットオプション]
--[詳細設定]
--[Java VM]もしくは[MicrosoftVM]
--[Javaコンソールの使用(再起動が必要)]をチェック
もしくは
--[Javaログの使用]をチェック
こうすることで、アプレットからの出力は
C:\WINDOWS\JAVA\javalog.txt
に出力されます。
Java Plug-in (Windows) の場合)
スタートメニューの Java Plug-in 関連のメニューで
Java コンソールを表示できます。
[S003 Q-12]
発生した例外の詳細を知りたいのですが?
[S003 A-12]
toStringメソッドもしくは printStackTraceメソッドを使いましょう。
前者は単純に発生した例外の名前と簡単なメッセージを出力します。
また、後者はtoStringメソッドの結果に加えて、スタックフレームの
情報まで出力します。
例)
public class DivideByZeroTest {
public static void main(String[] args) {
int kotae;
int bunbo = 2;
try {
kotae = bunbo / 0;
} catch(ArithmeticException ae) {
System.err.println("----- toString() -----");
System.err.println(ae.toString());
System.err.println("----- printStackTrace() -----");
ae.printStackTrace();
} finally {
System.exit(0x7f);
}
}
}
このようなプログラムを実行すると、次のような出力が得られます。
----- toString() -----
java.lang.ArithmeticException: / by zero
----- printStackTrace() -----
java.lang.ArithmeticException: / by zero
at DivideByZeroTest.main(DivideByZeroTest.java, Compiled Code)
contributor: miyazaki
コメントの送り先:Java FAQ BBS