29

aがスローされたときに、JVM がどのポインター (またはより正確にはどの変数) が null であるかを通知しないのはなぜなのか、私はいつも疑問に思っていました。NullPointerException

問題のある行には、エラーの原因となった可能性のある多数の変数が含まれていることが多いため、行番号は十分に具体的ではありません。

これらの例外メッセージをより便利にするコンパイラまたは JVM フラグはありますか?

4

7 に答える 7

51

これは、使用可能な名前がない場合に常に逆参照が発生するためです。値はオペランド スタックにロードされ、逆参照する JRE オペコードの 1 つに渡されます。ただし、オペランド スタックには、NULL 値に関連付ける名前がありません。それが持っているのは「ヌル」だけです。巧妙な実行時追跡コードを使用して名前を導出することはできますが、それによってオーバーヘッドが追加され、価値が制限されます。

このため、ヌル ポインター例外の追加情報をオンにする JRE オプションはありません。

この例では、参照はローカル スロット 1 に格納され、ローカル変数名にマップされます。しかし、逆参照は、invokevirtual 命令で発生します。これは、スタック上で「null」値のみを認識し、例外をスローします。

15 aload_1
16 invokevirtual #5 

逆参照が続く配列ロードも同様に有効ですが、この場合、「null」値にマップする名前はなく、別の値のインデックスだけです。

76 aload    5
78 iconst_0
79 aaload
80 invokevirtual #5

名前を各命令に静的に割り当てることもできません。この例では大量のバイトコードが生成されますが、逆参照命令が objA または objB のいずれかを受け取ることがわかります。これを動的に追跡して正しいものを報告する必要があります。両方の変数が同じ逆参照命令に流れるため:

(myflag ? objA : objB).toString()
于 2009-07-22T22:03:38.103 に答える
12

コードを JIT すると、それは単なるネイティブ ポインター演算になり、ネイティブ コード内のいずれかのポインターが null の場合、例外がスローされます。そのアセンブリを元の変数に戻すことは、パフォーマンスに壊滅的な影響を与える可能性があり、JIT が生成されたコードをさまざまなレベルに最適化することを考慮すると、それはしばしば不可能です。

于 2009-07-22T21:09:48.523 に答える
0

残念ながら、これはJavaの動作方法です。

これが「あなたの」コードである場合は、次のようなスニペットを追加するだけです。

if (foo == null) {
  throw new NullPointerException("foo == null");
}

fooを割り当てた直後。fooがパラメーターの場合は、メソッド本体の先頭ですぐに確認し、代わりにIllegalArgumentExceptionをスローします。

これは、問題を明確にするのに役立つはずです。

于 2009-07-22T21:59:49.933 に答える
0

例外の正確な原因を取得するために、デバッグ時に Eclipse のヌル ポインター例外にブレークポイントを追加できます。

于 2009-08-14T13:42:27.473 に答える
0

1 行で複数のメソッド呼び出しを行うのではなく、行を複数の行に分割するか、その行にブレークポイントを設定してデバッガーでその行をステップ実行すると、どの参照が null であるかを非常に簡単に判断できます。

于 2009-07-22T21:14:24.317 に答える
0

もしも

問題のある行には、エラーの原因となった可能性のある多数の変数が含まれていることが多いため、行番号は十分に具体的ではありません。

それから私は提案します:

  1. その行を複数の行に分割し、可能なNullPointerException生成値を一時変数に割り当てます。
  2. デバッガーを使用して、問題の原因となっているメソッドが見つかるまで、各メソッド呼び出しをステップ実行します。
于 2009-07-22T21:15:47.653 に答える