1

次のような Java コードがあるとします。

getPerson().getParent().getSiblings().first().getName()

そして、その行で NullPointerException が発生します。どちらが null であるかをどのように判断しますか? デバッグしてすべての呼び出しを確認するか、チェーンを一時的に複数の行に分割することができます。

ただし、少し前に実行されるオープンソース プロジェクトを見たのを覚えています。これは、null の結果を返すメソッド呼び出しを行った NullPointerException のスタック トレースを向上させる javaagent だと思います。残念ながら、私はそれを見つけることができないようです。それがどのように行われるか、またはそれがどのツールであったかを誰かが知っていますか?

4

5 に答える 5

1

面白い。

人はnullの親を持つことができますか?(有性生殖する存在には2人の親がいませんか?)

あなたが一人っ子の場合はどうなりますか?getSiblings()は何を返す必要がありますか?nullまたは、さらに良いことに、空のコレクション?

名がない場合はどうなりますか?スティングまたはマドンナはファーストネームですか、それともラストネームですか?最初の場合、姓は何を返しますか?

ここでの本当の問題はデザインです。nullの場合に何をすべきかについて十分に考えていません。それを理解する方が良いです。

于 2011-07-22T15:33:14.270 に答える
1

IMHO it is a better style when you don't put in one line methods which may throw npe. Then you don't have such a problem :) Even putting each invocation in a single line (but the same instruction like method1()\n.method2() and so one) is not a good idea. Simple code reformatting can put them back in one line.

If method may return null you should really check the return value each time. If the method should not return null, the getter should contain a check and throw an exception (IllegalStateException?) instead of returning null.

You can add to existing code such a check with AspectJ and load-time veave (using javaagent).

For example:

/** Throw Error if a method for creating a Point returns null */
after () returning (Point p) : 
    call(Point+ SubPoint+.create(..)) {
    if (null == p) {
        String err = "Null Point constructed when this (" 
            + thisJoinPoint.getThis() 
            + ") called target (" 
            + thisJoinPoint.getTarget() 
            + ") at join point (" 
            + thisJoinPoint.getSignature() 
            + ") from source location (" 
            + thisJoinPoint.getSourceLocation()
            + ") with args ("
            + Arrays.asList(thisJoinPoint.getArgs())
            + ")";
        throw new Error(err);
    }
}
于 2011-07-22T15:27:24.623 に答える
0

私の意見では、これは保守可能なコードよりも簡潔なコードの問題です。関数を連鎖させると、コードがすっきりと見えるようになりますが、長期にわたって維持するのが難しいコードベースにつながる可能性があります。操作を分離すると、機能が長くなる可能性がありますが、バグを追跡する方がはるかに簡単です。

于 2011-07-22T15:34:03.940 に答える
0

OPが求めているものよりもはるかに複雑になっている人もいると思います

チェーンされた各メソッドを独自の行に配置するだけです。

getPerson()
.getParent()
.getSiblings()
.first()
.getName();

そして、NPE がどのメソッドであるかを示す正しい行番号を取得します (前の行は null を返しています)。

はい、あらゆる種類の堅牢な NPE チェックを実行できますが、最終的には、単に作業を完了する必要があり、null が予期されない可能性があるため、他のエラー処理でシュガー コーティングしないでください。

オブジェクトとその子に検証注釈を追加することで、これを防ぐこともできます。オブジェクトを検証してから、オブジェクト ツリーのウォークに進みます。これは過去に私にとってうまくいきました。これにより、再利用可能な自動エラー処理が向上します。さらに、どのメソッドが null を返すことができるかを文書化しています。

最も人気のあるJavascript(jQuery)ライブラリの1つが常にそれを使用しているため、連鎖をサポートするために設計が悪いと言うのは公平ではないと思います(そして、時々null/未定義の値を返します)。

于 2011-07-22T15:39:35.573 に答える
0

理想的には、各メソッドの戻り値を変数に割り当てて、それらを検査するだけで済みます。とにかく、それはコンパイラが一時変数を内部的に処理することです。

書き直す気がない場合は、その行にブレークポイントを設定してから、各関数のウォッチを追加する (最も簡単な方法) か、(IDE でサポートされている場合) 各関数を 1 つずつ入力することができます。 「即時」ウィンドウに時間を入力して、何が戻ってくるかを確認してください。

于 2011-07-22T15:30:14.267 に答える