私は自分のアプリケーションを実行するときに時々それは私のようなエラーを私に与える:
Exception in thread "main" Java.lang.NullPointerException
at com.example.myproject.Book.getTitle(Book.Java:16)
at com.example.myproject.Author.getBookTitles(Author.Java:25)
at com.example.myproject.Bootstrap.main(Bootstrap.Java:14)
人々はこれを「スタックトレース」と呼んでいます。 スタックトレースとは何ですか? 自分のプログラムで発生しているエラーについて教えてください。
この質問について - 私は初心者のプログラマーが「エラーを起こしている」ところで質問をすることがよくあります、そして彼らは単にスタックトレースが何であるか彼らができることを理解せずこれを使って。この質問は、スタックトレースの価値を理解するのに手助けが必要な初心者プログラマのための参考資料です。
簡単に言うと、 スタックトレース は、例外がスローされたときの中間にあったメソッド呼び出しのリストです。
簡単な例
問題の例では、アプリケーション内のどこで例外がスローされたのかを正確に判断できます。スタックトレースを見てみましょう。
Exception in thread "main" Java.lang.NullPointerException
at com.example.myproject.Book.getTitle(Book.Java:16)
at com.example.myproject.Author.getBookTitles(Author.Java:25)
at com.example.myproject.Bootstrap.main(Bootstrap.Java:14)
これは非常に単純なスタックトレースです。 「at ...」のリストの先頭から始めると、エラーが発生した場所を特定できます。私たちが探しているのは、アプリケーションの一部である 一番上の メソッド呼び出しです。この場合、それは:
at com.example.myproject.Book.getTitle(Book.Java:16)
これをデバッグするために、Book.Java
を開いて16
行を見てください。
15 public String getTitle() {
16 System.out.println(title.toString());
17 return title;
18 }
これは、上記のコードで何か(おそらくtitle
)がnull
であることを示しています。
一連の例外を含む例
アプリケーションは例外をキャッチし、それを別の例外の原因として再スローすることがあります。これは通常次のようになります。
34 public void getBookIds(int id) {
35 try {
36 book.getId(id); // this method it throws a NullPointerException on line 22
37 } catch (NullPointerException e) {
38 throw new IllegalStateException("A book has a null property", e)
39 }
40 }
これにより、スタックトレースが表示されることがあります。
Exception in thread "main" Java.lang.IllegalStateException: A book has a null property
at com.example.myproject.Author.getBookIds(Author.Java:38)
at com.example.myproject.Bootstrap.main(Bootstrap.Java:14)
Caused by: Java.lang.NullPointerException
at com.example.myproject.Book.getId(Book.Java:22)
at com.example.myproject.Author.getBookIds(Author.Java:36)
... 1 more
これと違うのは「原因」です。場合によっては、例外に複数の「原因」セクションがあります。これらの場合、通常は「根本原因」を見つける必要があります。これは、スタックトレースの最も低い「原因」セクションの1つになります。私たちの場合、それは:
Caused by: Java.lang.NullPointerException <-- root cause
at com.example.myproject.Book.getId(Book.Java:22) <-- important line
繰り返しますが、この例外を除いて、ここでNullPointerException
が発生する原因を確認するには、22
のBook.Java
行を見てください。
ライブラリコードを使ったもっとやっかいな例
通常、スタックトレースは上記の2つの例よりもはるかに複雑です。例を示します(長い例ですが、いくつかのレベルの連鎖例外を示しています)。
javax.servlet.ServletException: Something bad happened
at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.Java:60)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.Java:1157)
at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.Java:28)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.Java:1157)
at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.Java:33)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.Java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.Java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.Java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.Java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.Java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.Java:418)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.Java:152)
at org.mortbay.jetty.Server.handle(Server.Java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.Java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.Java:943)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.Java:756)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.Java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.Java:404)
at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.Java:228)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.Java:582)
Caused by: com.example.myproject.MyProjectServletException
at com.example.myproject.MyServlet.doPost(MyServlet.Java:169)
at javax.servlet.http.HttpServlet.service(HttpServlet.Java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.Java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.Java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.Java:1166)
at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.Java:30)
... 27 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.Java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.Java:66)
at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.Java:64)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.Java:2329)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.Java:2822)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.Java:71)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.Java:268)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.Java:321)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.Java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.Java:130)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.Java:210)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.Java:56)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.Java:195)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.Java:50)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.Java:93)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.Java:705)
at org.hibernate.impl.SessionImpl.save(SessionImpl.Java:693)
at org.hibernate.impl.SessionImpl.save(SessionImpl.Java:689)
at Sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:25)
at Java.lang.reflect.Method.invoke(Method.Java:597)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.Java:344)
at $Proxy19.save(Unknown Source)
at com.example.myproject.MyEntityService.save(MyEntityService.Java:59) <-- relevant call (see notes below)
at com.example.myproject.MyServlet.doPost(MyServlet.Java:164)
... 32 more
Caused by: Java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...]
at org.hsqldb.jdbc.Util.throwError(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.Java:105)
at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.Java:57)
... 54 more
この例では、もっとたくさんあります。私たちが最も心配しているのは、 私たちのコード から来ているメソッドを探すことです。これはcom.example.myproject
パッケージに含まれるものです。上の2番目の例から、まず根本的な原因を探してみましょう。
Caused by: Java.sql.SQLException
ただし、その下のすべてのメソッド呼び出しはライブラリコードです。それでは、その上の "Caused by"に移動して、コードから始まる最初のメソッド呼び出しを探します。
at com.example.myproject.MyEntityService.save(MyEntityService.Java:59)
前の例のように、MyEntityService.Java
の行で59
を見てください。それがこのエラーが発生した場所です(SQLExceptionがエラーを示しているので、これは少し明らかに間違っていましたが、デバッグ手順は後にあります)。
私はこの答えを投稿しているので、一番上の答え(アクティビティでソートされたとき)は、単なる間違ったものではありません。
Stacktraceとは何ですか?
スタックトレースは非常に便利なデバッグツールです。キャッチされていない例外がスローされた時点(またはスタックトレースが手動で生成された時点)の呼び出しスタック(つまり、その時点までに呼び出された関数のスタック)が表示されます。エラーが発生した場所だけでなく、コードのその場所でプログラムがどのように終了したかも表示されるため、これは非常に便利です。これは次の質問につながります。
例外とは何ですか?
例外は、エラーが発生したことをランタイム環境がユーザーに知らせるために使用するものです。一般的な例は、NullPointerException、IndexOutOfBoundsException、またはArithmeticExceptionです。あなたが不可能である何かをやろうとするとき、これらのそれぞれは引き起こされます。たとえば、Nullオブジェクトを間接参照しようとすると、NullPointerExceptionがスローされます。
Object a = null;
a.toString(); //this line throws a NullPointerException
Object[] b = new Object[5];
System.out.println(b[10]); //this line throws an IndexOutOfBoundsException,
//because b is only 5 elements long
int ia = 5;
int ib = 0;
ia = ia/ib; //this line throws an ArithmeticException with the
//message "/ by 0", because you are trying to
//divide by 0, which is not possible.
Stacktraces/Exceptionsをどのように扱うべきですか?
最初に、例外の原因を突き止めてください。例外の名前をGoogleで調べて、その例外の原因を調べます。ほとんどの場合、それは誤ったコードによって引き起こされます。上記の例では、すべての例外が誤ったコードによって引き起こされています。したがって、NullPointerExceptionの例では、その時点でa
がnullにならないようにすることができます。たとえば、a
を初期化したり、次のようなチェックを含めることができます。
if (a!=null) {
a.toString();
}
このように、a==null
の場合、問題の行は実行されません。他の例についても同様です。
時にはあなたはあなたが例外を受けないことを確認できない。たとえば、プログラムでネットワーク接続を使用している場合、コンピュータがインターネット接続を失うのを止めることはできません(たとえば、ユーザーがコンピュータのネットワーク接続を切断するのを止めることはできません)。この場合、ネットワークライブラリはおそらく例外をスローします。これで、例外をキャッチして handle itにする必要があります。つまり、ネットワーク接続の例では、接続を再度開くか、ユーザーまたはそのようなものに通知するようにしてください。また、catchを使用するときは常に、常に捕捉したい例外のみを捕捉してください。 すべての例外を捕捉するcatch (Exception e)
のような広範なcatchステートメントは使用しないでください。そうでなければ、誤って間違った例外をキャッチして間違った方法で反応する可能性があるので、これは非常に重要です。
try {
Socket x = new Socket("1.1.1.1", 6789);
x.getInputStream().read()
} catch (IOException e) {
System.err.println("Connection could not be established, please try again later!")
}
なぜcatch (Exception e)
を使わないのですか?
小さな例を使用して、すべての例外を捕捉できない理由を説明しましょう。
int mult(Integer a,Integer b) {
try {
int result = a/b
return result;
} catch (Exception e) {
System.err.println("Error: Division by zero!");
return 0;
}
}
このコードが実行しようとしているのは、0による除算が原因で発生する可能性のあるArithmeticException
をキャッチすることです。ただし、NullPointerException
またはa
がb
の場合にスローされる可能性のあるnull
もキャッチします。これはNullPointerException
を受け取るかもしれないが、それをArithmeticExceptionとして扱い、おそらく間違ったことをすることを意味します。最良のケースでは、NullPointerExceptionがあったことを見逃しています。そのようなものはデバッグをより困難にするので、そうしないでください。
_ tldr _
不可能な場合は、特定の例外をキャッチして処理します。
catch (Exception e)
を使用せず、常に特定の例外をキャッチします。それはあなたに多くの頭痛を救うでしょう。ロブが述べたことに追加します。アプリケーションにブレークポイントを設定すると、スタックの段階的な処理が可能になります。これにより、開発者はデバッガを使用して、メソッドが予期しないことを実行している正確な時点を確認できます。
RobはNullPointerException
(NPE)を使用して一般的なものを説明しているため、次の方法でこの問題を解決できます。
次のようなパラメータを取るメソッドがある場合:void (String firstName)
このコードでは、firstName
に値が含まれていることを評価します。これは次のようにします。if(firstName == null || firstName.equals("")) return;
上記により、firstName
を安全でないパラメーターとして使用できなくなります。したがって、処理する前にnullチェックを行うことで、コードが適切に実行されることを確認できます。メソッドでオブジェクトを利用する例を拡張するために、ここを見ることができます:
if(dog == null || dog.firstName == null) return;
上記はnullをチェックするための適切な順序です。ベースオブジェクト(この場合はdog)から始めて、処理の前にすべてが有効であることを確認するために可能性のツリーを歩き始めます。順序を逆にすると、NPEがスローされ、プログラムがクラッシュする可能性があります。
Throwableファミリが提供するもう1つのスタックトレース機能があります - 操作する可能性 /スタックトレース情報。
標準の動作:
package test.stack.trace;
public class SomeClass {
public void methodA() {
methodB();
}
public void methodB() {
methodC();
}
public void methodC() {
throw new RuntimeException();
}
public static void main(String[] args) {
new SomeClass().methodA();
}
}
スタックトレース:
Exception in thread "main" Java.lang.RuntimeException
at test.stack.trace.SomeClass.methodC(SomeClass.Java:18)
at test.stack.trace.SomeClass.methodB(SomeClass.Java:13)
at test.stack.trace.SomeClass.methodA(SomeClass.Java:9)
at test.stack.trace.SomeClass.main(SomeClass.Java:27)
操作されたスタックトレース:
package test.stack.trace;
public class SomeClass {
...
public void methodC() {
RuntimeException e = new RuntimeException();
e.setStackTrace(new StackTraceElement[]{
new StackTraceElement("OtherClass", "methodX", "String.Java", 99),
new StackTraceElement("OtherClass", "methodY", "String.Java", 55)
});
throw e;
}
public static void main(String[] args) {
new SomeClass().methodA();
}
}
スタックトレース:
Exception in thread "main" Java.lang.RuntimeException
at OtherClass.methodX(String.Java:99)
at OtherClass.methodY(String.Java:55)
名前を理解するには :スタックトレースは、最も表面的な例外(例:Service Layer Exception)から最も深いもの(例:Service Layer Exception)までの例外のリスト(または「原因による」のリスト)です。データベース例外)。スタックが先入れ先出し(FILO)であるという理由とまったく同じように、スタックは最初から最後まで発生し、その後一連の例外が発生し、表面的な例外が最後に発生しました。 1つは間に合ったが、私たちはそもそもそれを見ます。
Key 1 :ここで理解しておく必要がある重要なことは、最も深い原因が「根本的な原因」ではない可能性があるということです。その層よりも深いです。たとえば、不正なSQLクエリを実行すると、シンタックスエラーの代わりにSQLServerException接続がボットムでリセットされることがあります。これは、スタックの途中で発生する可能性があります。
Key 2 :もう1つの注意が必要だが重要なことは各 "Cause by"ブロックの内側にあり、最初の行が最も深い層であり、このブロックの最初の場所にある。例えば、
Exception in thread "main" Java.lang.NullPointerException
at com.example.myproject.Book.getTitle(Book.Java:16)
at com.example.myproject.Author.getBookTitles(Author.Java:25)
at com.example.myproject.Bootstrap.main(Bootstrap.Java:14)
Book.Java:16がBootstrap.Java:14によって呼び出されたAuther.Java:25によって呼び出された、Book.Java:16が根本的な原因でした。ここにダイアグラムを添付してトレーススタックを時系列でソートします。
他の例に加えて、 内側の(入れ子になった)クラス があり、それらは$
記号で現れます。例えば:
public class Test {
private static void privateMethod() {
throw new RuntimeException();
}
public static void main(String[] args) throws Exception {
Runnable runnable = new Runnable() {
@Override public void run() {
privateMethod();
}
};
runnable.run();
}
}
このスタックトレースになります:
Exception in thread "main" Java.lang.RuntimeException
at Test.privateMethod(Test.Java:4)
at Test.access$000(Test.Java:1)
at Test$1.run(Test.Java:10)
at Test.main(Test.Java:13)
他の記事ではスタックトレースとは何かについて説明していますが、それでもまだ作業が難しい場合があります。
スタックトレースを取得して例外の原因をトレースしたい場合は、 Javaスタックトレースコンソール in Eclipse を使用することを理解するのに良い出発点です。別のIDEを使用している場合は、同様の機能があるかもしれませんが、この回答はEclipseに関するものです。
まず、すべてのJavaソースがEclipseプロジェクト内でアクセス可能であることを確認してください。
次に、 Java パースペクティブで、 Console タブをクリックします(通常は一番下にあります)。コンソールビューが表示されていない場合は、メニューオプション ウィンドウ - >ビューの表示 に進み、 コンソール を選択します。
それからコンソールウィンドウで、(右側の)次のボタンをクリックしてください。
次に、ドロップダウンリストから[ Java Stack Trace Console ]を選択します。
スタックトレースをコンソールに貼り付けます。それはあなたのソースコードと利用可能な他のソースコードへのリンクのリストを提供します。
これはあなたが見るかもしれないものです(Eclipseドキュメンテーションからの画像):
最後に行われたメソッド呼び出しは、スタックの top になります。これは最上行です(メッセージテキストを除く)。スタックを降りることは時間的にさかのぼります。 2行目は1行目などを呼び出すメソッドです。
オープンソースソフトウェアを使用している場合、調べたい場合は、ソースをダウンロードしてプロジェクトに添付する必要があります。プロジェクト内のソースjarファイルをダウンロードし、 Referenced Libraries フォルダを開いてオープンソースモジュール用のjarファイル(クラスファイルを含むもの)を見つけ、右クリックして Properties を選択します。元のjarファイルを添付してください。