web-dev-qa-db-ja.com

NullPointerExceptionをキャッチしてもよいのはいつですか?

効果的Java catchNullPointerExceptionをすべきではないことをお勧めします。それは常に正しいですか?

NullPointerExceptionをキャッチする多くの場合、catchbodyはprintStackTrace()のみを呼び出します。

NullPointerExceptionをキャッチせずにprintStackTrace()を呼び出した場合、exceptionが発生した場所を確認するにはどうすればよいですか?

また、NullPointerExceptionをキャッチし、catch本体が空の場合、その時点でスタック情報を取得できません。

[〜#〜] update [〜#〜]

私はグーグルAndroidソース、AOSP4.2.2_r1.2でRuntimeExceptionをキャッチする統計を分析しました。

249のRuntimeExceptionキャッチがあり、以下はキャッチボディの統計です。

42%: throw it again as other Exceptions (RuntimeException: 33%, others: 8%)

32%: just return null or 0/false/true or other default values

14%: just call log or printstacktrace

5%: just comment like "// Fall through.", "// ignore, not a valid type.", "// system process dead", "// do nothing"

2%: empty body

3%: display error messages or send fail codes (ex. network service discovery failed: replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); )


3%: intialize or reset related variables.

ほとんどの場合、dalvikと外部は他の例外をスローすることでNPEを処理します。

ただし、フレームワークは通常、nullまたはその他の値を返すことで処理します。

  1. キャッチボディで他の例外をスローすることは悪いことでも良いことでもないと思いますか?

  2. NPEがより高いレベル(アプリケーションなど)で発生し、アプリが完全に独立しているために例外が重要ではないことを開発者が確認した場合、開発者がキャッチしてNPEを無視することを受け入れることができますか?

後もう一つ、

Google AndroidフレームワークのソースコードはRuntimeExceptionの面で不安定である可能性があると結論付けることができますか?

18
500004dolkong

効果的Java NullPointerExceptionをキャッチしないことをお勧めします。常に正しいですか?

ほとんどすべての場合、それは正しいです。

NullPointerExceptionは通常、バグの結果です。つまり、アプリケーションが予期しない状況でnullオブジェクト参照に遭遇し、それを使用しようとしました。このシナリオでは、あなた(プログラマー)がnullを予期していなかったため、tryを回復しても安全かどうかを知ることはほぼ不可能です。 、および/またはどのような「修復」が必要かを知るため。したがって、最善の方法は、NPEを基本レベルに伝播させてから、それを一般的なバグとして扱うことです。 (「ネットワークサービス」アプリケーションでは、「サービスエラー」応答を返し、続行を試みることが適切な場合があります。)

もう1つのシナリオは、あなた(プログラマー)がnullが配信される可能性があると予想する場合です。この場合、最善の戦略は(ほぼ常に)nullbeforeを使用しようとすることを明示的にテストすることです。これにより、avoidingNPE ...そしてそれを処理する必要性。これには2つの理由があります。

  • 例外処理は通常、費用がかかります。実際、何桁もnullのテストよりも費用がかかる可能性があります。

  • 予期されたNPEの発生を許可してからそれをキャッチすると、他のunexpectedNPEもキャッチして誤って処理する可能性があります。


私は「ほぼ常に」と言って上記を修飾したことに注意してください。理論的には、nullの明示的なテストによってコードが乱雑になり、少なくともConsideringNPEを実行できるようにする価値があるというシナリオが考えられます。 。ただし、コードによっては、予期しないNPEが発生する可能性もあります。したがって、このアプローチは常に潜在的に脆弱です。

(FWIW-これが良い考えであるという実際のケースに遭遇したことはありません...)


NullPointerExceptionをキャッチする多くの場合、catch bodyはprintStackTrace()のみを呼び出します。

それはおそらく悪いコードです。何もしないことがNPEから回復する正しい方法になることはめったにありません。

NullPointerExceptionをキャッチせずにprintStackTrace()を呼び出す場合、例外が発生した場所を確認するにはどうすればよいですか?

NPEを基本レベルに伝播させます。そこで、all未処理の例外のスタックトレースをキャッチして出力(またはログに記録)し、それが可能であれば、救済するか、回復を試みます。

また、NullPointerExceptionをキャッチし、キャッチボディが空の場合、その時点でスタック情報を取得できません。

決して、これをしないでください!これは「押しつぶし」と呼ばれ、危険です。 (特に、上で説明したように、NPEは、ユーザー/コードが予期していなかったことが原因である可能性があるためです。)

いいえ、これを行うと、スタックトレースを取得できません。なくなった。


[〜#〜]フォローアップ[〜#〜]

私は「NPEを回避する」ためのいくつかの一般的な戦略にあまり信頼/信頼を置いていません1。たとえば、次のようなものです。

_return (someObject != null) ? someObject.toString() : "";
_

プログラマーが問題について考えていないであることに常に疑いを抱かせます。そもそもsomeObjectnullだったのはなぜですか?

NPEは、予期しない場所にnullがあることが原因で発生します。そのため、NPEは通常、実際の問題自体ではなく、問題の症状です。私の考えでは、NPEは避けるべきものではありません。むしろ、NPEを使用して、予期しないnullroot causeを見つけて修正する必要があります。 NPEを回避する上記のようなコードは、その目標の邪魔になります。

したがって、予期しない場所でnull値を回避するための戦略を優先/推奨します。

  • nullmeanful値でない限り、すべての参照フィールドがnull以外の値に初期化されることを確認してください。

  • 特に代替手段がある場合は、意味のある値としてnullを使用しないようにしてください。たとえば、空の文字列、長さゼロの配列、空のコレクション、「未定義」を意味する識別されたインスタンスなどです。または、Java 8以降の場合は、Optionalを使用します。

  • nullをエラーまたは特別な場合の兆候として返さないでください。 (例外をスローするか、識別値を返します。)

  • 予期しないnull値(例:null引数)を早期にチェックし、NPE後でではなく早くをスローします。

  • null引数または結果が正当であるいくつかの場所では、javadocsがこれを明確かつ明示的に文書化することを確認してください。ドキュメントがない場合は、nullは許可されておらず、返されません。

そして、NPEを取得する場合は常に、問題のrealソースを見つけて修正するようにしてください...例外をスローした特定のステートメントだけではありません。

1-標準のJava APIで、nullが戻り値として使用(または悪用)されている場所について知ることには価値があります。たとえば、Class.getResourceAsStream(...)またはHttpRequest.getParam(...)。これらの「NPEを回避するためのアドバイス」ドキュメントは、これらのトラップを指摘するのと同じくらい役に立ちます。

37
Stephen C

NullPointerExceptionは通常、コードの論理エラーが原因で発生します。安全でない操作を回避することで、NullPointerExceptionを排除できます。それでもNullPointerExceptionが発生する場合は、StackTraceで確認できます。

例えば

if (Obj.getName("Sam")) {
    // only executes if Obj != null
}  

次のようにNullPointerExceptionを回避できます

if (Obj == null){
    System.out.println("Null Obj, Can't proceed");
} else {
    Obj.getName("Sam")
}

一般に、NullPointerExceptionをキャッチせず、JVMで処理することをお勧めします。

しかし、それはすべて異なります。たとえば、次のように言います。List<Student> listStudent = getAllStudent();のようなコードがある場合

ここでgetAllStudent()はDBに接続して結果を表示します。ここで、リストオブジェクトに対して操作を実行する前に、

if(listStudent != null){ 
    //do the task. 
}else{ 
    //Show Message like no student is there instead of catching NullPointerException 
}

そうしないと、データがない場合にNullPointerExceptionが発生する可能性があります。

したがって、より良い方法は、Nullをチェックすることですが、次のように処理しないことです。

try{ 

}catch(NullPointerException e){

}
2
Jayesh

慣例では、実行時の例外をキャッチしないようにします。理由は次のとおりです。何か恐ろしいがうまくいかなかったので、開発者としてのあなたは30分前にそれを修正することに熱心でなければなりません。

NullPointerException は、実際にはRuntimeExceptionのサブクラスです。 RuntimeExceptionの親を持つ他のクラスと同様に、それらはuncheckedと見なされます。したがって、NPEを生成する場合でも、コードはコンパイルされます。

// This would appropriately return "false", if the order were reversed 
// and something was empty.
public boolean doSomething(String something) {
    String hello = null;
    if(hello.equals(something)) {
        System.out.println("Wow");
    }
}

明示的にあらゆる種類のランタイム例外をキャッチすることは、プログラムの過程で恐ろしい、悪いことが起こると予想し、その事実を理解したいことを示します。

catchブロックの本体に何が入るかについては、おそらくIDEによって自動的に生成されています。アプリケーションの上位レベルに例外を伝播しない場合は、プログラムが爆発した理由に関する有用なコンテキストを取得する必要があります。

Catchブロックに何も入れない場合、それは黙って無視されます-これはbadです。

1
Makoto

通常、NullPointerExceptionは、APIの使用法に論理エラーがあるか、実行された値が欠落していることを示します。そのため、元に戻すことをお勧めします。しかし、あなたはそれを捕まえることができます。実質的に

渡されたnullパラメータにデフォルト値を指定する場合はキャッチすることをお勧めします。

例えば ​​:

タイムアウト値は構成可能であり、ユーザーがそれを渡す必要があることを期待しています。しかし、ユーザーはそれを渡すのを忘れています。このシナリオでは、NPEをキャッチし、パラメーターにデフォルト値を使用しているという警告をログに記録できます。

1
java_enthu

本当に重要理由がない限り、空のcatchブロックを使用しないでください。通常、そのような理由はありません。

通常、変数がnullかどうかを確認するか、NPEをキャッチして、より適切な理由をスローすることをお勧めします。たとえば、メソッドgetCar()nullを返した場合、carのメソッドを呼び出そうとしたときに、NPEをキャッチしたり、車がnullであるかどうかを確認したりできます。 RuntimeExceptionをスローします(ただし、状況が本当に例外的な場合のみ)。したがって、エラーをより抽象的にバインドし、理解しやすくします。

1
Maxim Efimov

NullPointerExceptionは、まだ初期化されていないオブジェクトにアクセス/変更しようとするコード内の状況です。

これは基本的に、オブジェクト参照変数がどこも指しておらず、何も参照していないか「null」であることを意味します。

ジョシュア・ブロックin effective Javaは言う:

「間違いなく、すべての誤ったメソッド呼び出しは、違法な引数または違法な状態に要約されますが、特定の種類の違法な引数および状態には、他の例外が標準的に使用されます。呼び出し元がnull値が禁止されているパラメーターでnullを渡した場合、慣例により、IllegalArgumentExceptionではなくNullPointerExceptionがスローされます。」

したがって、コードの一部の場所でNullPointerExceptionを許可する必要がある場合は、通常よりも有益なものにするようにしてください。

ここから効果的なNPE処理の詳細をお読みください。

1
Ankur Lathi

例外がスローされると、それが例外であっても、jvmは最も近いhandler(catchブロック)を探します。現在のメソッドで見つからない場合は、呼び出し元のコードなどでハンドラーを探します。 SO基本的に_calling stack_全体をボトムアップで検索して、上記の例外を処理できるcatchブロックを探します。ハンドラーが見つからない場合、jvmはe.printStackTrace()を呼び出すデフォルトのハンドラーを使用します。

現在、NullPointerExceptionは実行時の例外であり、基本的にコードの論理的な誤謬を示しています。 mayがそれをキャッチしたい場合があります。しかし、サムルールとして:

  • ランタイム例外をキャッチしないでください。通常、論理エラーを指します。
  • 空のcatchブロックを残さないでください。キャッチしたが、それに基づいて行動しないと、スタックトレースと例外が失われます。
  • スタックトレースを標準の出力に出力するだけでなく、必要に応じて後で分析するためにどこかにログに記録します。
1
rocketboy

堅牢でユーザー中心のコードは、それについて何かできることがあれば、そのような「致命的なエラー」をキャッチしようとする必要があります。試行された関数呼び出しを再試行できます。おそらく、このnull例外は、一時的なものが原因です。本当に例外をスローするべきではなく、一時的な障害に対してより適切にコーディングする必要があるものですが、エンドユーザーが必要なものを取得することを思いとどまらせるべきではなく、長いステートフルフォーム入力プロセスである可能性があるものを放棄するだけです。ユーザーの電子メール設定を入力するなど、最後のまったく重要でないステップで、nullポインターエラーが発生し、ユーザーの既存の入力が破棄されます。

0
Andyz Smith