Java プログラムが失敗する最も一般的な原因の 1 つは、NullPointerException です。
最も単純なケースとして、コンパイラーは、次のようなコードを検出するときに直接警告することができます。
Object o = null;
String s = o.toString();
例外の分岐、ループ、およびスローでは、プログラムで使用される一部またはすべてのパスに出現する間接参照されている変数に NULL/非 NULL 値が代入されているかどうかを確認するために、かなり高度なフロー分析が必要になります。
フロー分析には特有の複雑さがあるため、小さい塊で実行するのが最適です。 システムを一括分析する方法は、Eclipse Java コンパイラーの範囲を超えています。 一方、一度に 1 つのメソッドを分析するなら、良好なパフォーマンスでツールを実行できます。 この方法の利点は、分析が高速で、タイプ入力時にコンパイラーが直接警告できるように少しずつ実行できるという点です。 この欠点は、分析で、どのような値 (NULL か非 NULL) がメソッド間を (パラメーターおよび戻り値として) 流れているかを「見る」ことができないという点です。
このような状況に対処するため、NULL 注釈が使用されます。
メソッド・パラメーターを @NonNull として指定することにより、この位置では NULL 値を使用しない ことをコンパイラーに認識させることができます。
String capitalize(@NonNull String in) {
return in.toUpperCase(); // no null check required
}
void caller(String s) {
if (s != null)
System.out.println(capitalize(s)); // preceding null check is required
}
契約による設計 (Design-by-Contract) を実施する場合、これには次の 2 つの側面があります。
capitalize の実装者にとっては、引数 in は NULL にはならないという保証があるため、ここで NULL 検査をしなくても問題なく間接参照できます。
メソッド戻り値については、これとは対称的な状態になります。
@NonNull String getString(String maybeString) {
if (maybeString != null)
return maybeString; // the above null check is required
else
return "<n/a>";
}
void caller(String s) {
System.out.println(getString(s).toUpperCase()); // no null check required
}
Eclipse Java コンパイラーは、拡張 NULL 分析 (デフォルトでは無効) のために用意された次の 3 つの特殊な注釈型を使用するように構成できます。
@NonNull: NULL は有効な値ではありません@Nullable: NULL 値が許可されるので、その出現を想定する必要があります@NonNullByDefault: NULL 注釈がないメソッド・シグニチャーの型は、非 NULL として処理されます注釈 @NonNull および @Nullable は、次の場所でサポートされます。
@NonNullByDefault は、次の場所でサポートされます。
package-info.java を使用) - パッケージに含まれるすべての型に影響します
これらの注釈の実際の修飾名は構成可能ですが、デフォルトでは上記のものが使用される点に注意してください (パッケージ org.eclipse.jdt.annotation を使用)。
サード・パーティーの NULL 注釈を使用する場合、それらの注釈が少なくとも 1 つの @Target メタ注釈によって適切に定義されていることを必ず確認してください。そのように適切に定義されていないと、宣言注釈 (Java 5) と型注釈 (Java 8) の違いをコンパイラーが識別できなくなるためです。
デフォルトの NULL 注釈を持つ JAR ファイルが eclipse/plugins/org.eclipse.jdt.annotation_*.jar の Eclipse で提供されています。 この JAR は、コンパイル時にビルド・パス上に配置されている必要がありますが、実行時には不要です (そのため、コンパイル済みコードのユーザーには同梱する必要はありません)。
Eclipse Luna 以降では、この jar の 2 つのバージョンが存在し、1 つは Java 7 以前 (バージョン 1.1.x) で使用する宣言注釈を持つ jar で、もう 1 つは Java 8 (バージョン 2.0.x) で使用する NULL 型注釈を持つ jar です。
標準 Java プロジェクトの場合、@NonNull、@Nullable、または @NonNullByDefault への未解決の参照に関するクイック・フィックスもあり、適切なバージョンの JAR を次のようにビルド・パスに追加します。

OSGi バンドル/プラグインの場合、以下のいずれかのエントリーを MANIFEST.MF に追加してください。
Require-Bundle: ..., org.eclipse.jdt.annotation;bundle-version="[1.1.0,2.0.0)";resolution:=optional
Require-Bundle: ..., org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
互換性の対応するセクションに記されている事項も参照してください。
ここまでで、NULL 注釈は Java プログラムにさらに情報を追加するものであることがはっきりしたはずです (その情報は、後でコンパイラーで適切な警告を出すために使用できます)。 しかし、厳密に考えたとき、これらの注釈を使用してどのような情報を伝えますか? 実用的な観点で考えると、NULL 注釈を使って伝えることのできる情報には、少なくとも次の 3 つのレベルがあります。
(1) については、これ以上読まなくてもすぐに NULL 注釈を使い始めることができるでしょう。ただし、時折多少のヒントを示す以上の役割は期待できません。 これ以外のレベルについては、もう少し説明を加える必要があります。
単純に考えると、契約による設計において API 仕様のために NULL 注釈を使用するということは、すべての API メソッドのシグニチャーすべてに注釈を付けるしかないという意味になってしまいます。つまり、int などのプリミティブ型を除き、各パラメーターおよび各メソッド戻り型に @NonNull または @Nullable のいずれかのマークを付ける必要があるということになります。
これでは非常に多くの NULL 注釈を挿入することになるため、設計のしっかりしたコード (特に API メソッド) では @NonNull の出現頻度が @Nullable よりはるかに多いということを覚えておくと良いでしょう。
これを念頭に置くと、パッケージ・レベルで @NonNullByDefault 注釈を使用して、@NonNull をデフォルトとして宣言することにより、注釈の数を削減することができます。
ここで、@Nullable を使用することと NULL 注釈を省略することの大きな違いに注目してください。
この注釈は、NULL 使用が可能であること、そして NULL を想定しておく必要があることを明示的に示します。
対照的に、注釈がない場合、その意図が何かを知ることはできません。
以前にはこのような状況がよく見られ、両方 (呼び出し元と呼び出し先) が重複して NULL を検査することもあれば、両方とももう一方が検査を実行すると間違って想定することもありました。
それで NullPointerExceptions の使用が考え出されました。
注釈がなければコンパイラーが特定の通知を出すことはありませんが、@Nullable 注釈があると、すべての未検査間接参照にフラグが立てられます。
このような基本動作を利用すると、すべてのパラメーター注釈を事前条件に直接マップすることや、戻り注釈をメソッドの事後条件として解釈することができます。
オブジェクト指向プログラミングでは、契約による設計の概念により、もう 1 つの次元であるサブタイプとオーバーライドを扱う必要があります (この後の記述では、「オーバーライド」という用語は、Java 6 の @Override 注釈の意味で使用され、スーバータイプのメソッドで別のメソッドをオーバーライド、つまり実装する という意味になります)。
次のようなメソッドを呼び出すクライアントにおいて、
@NonNull String checkedString(@Nullable String in)
このメソッドのすべての実装 が契約を満たすものと想定することが可能でなければなりません。
そのため、インターフェース I1 にこのメソッド宣言がある場合、I1 を実装するクラス Cn の実装が実際には互換性のないものとなる可能性をすべて排除する必要があります。
特に、Cn がこのメソッドをオーバーライドする場合にパラメーターを @NonNull として宣言するような実装にすることは不正です。
仮に このような操作を許可してしまうと、I1 を利用するようにプログラミングされたクライアント・モジュールは、有効な引数として NULL を渡すことができますが、実装においては非 NULL 値を想定しているため、メソッド実装内部の未検査間接参照は許可されますが、実行時に問題が発生してしまいます。
したがって、@Nullable パラメーター指定を使用する場合、すべてのオーバーライド において、NULL を有効な値として予期する必要があります。
それとは逆に、@NonNull 戻り指定では、すべてのオーバーライド において、NULL が決して返されないようにする必要があります。
したがって、コンパイラーは、存在しない @NonNull パラメーター注釈 (または @Nullable 戻り注釈) がオーバーライドのときにスーパータイプに追加されないことを検査する必要があります。
興味深いことに、その逆の再定義である、@Nullable パラメーター注釈または @NonNull 戻り注釈を追加する操作は、正しい定義です。
その場合、メソッドが受け入れる値が多くなり、生成される戻り値がさらに限定的になるため、これをメソッドの「改善」と見なすことができます。
オーバーライドする側のあらゆるメソッドで NULL 注釈を繰り返すようサブクラスに強制することにより、継承階層を検索しなくても各メソッドの NULL 契約が分かります。ただし、出所が異なるコードが継承階層に混在している場合、すべてのクラスに対して NULL 注釈を一度に追加できない場合があります。こうした場合、NULL 注釈が欠落しているメソッドを、オーバーライドされるメソッドの注釈を継承した場合と同じように処理するよう、コンパイラーに指示できます。 このようにするためには、コンパイラー・オプションの NULL 注釈の継承を使用します。 NULL 契約が異なる 2 つのメソッドを 1 つのメソッドでオーバーライドすることが可能です。また、NULL 特性デフォルトは、継承された NULL 注釈と矛盾するメソッドでも適用可能です。 このような事例にはエラーのフラグが立てられます。矛盾を解決するために、オーバーライドする側のメソッドでは明示的な NULL 注釈を使用する必要があります。
@NonNull パラメーターを緩和して未指定にする?
NULL 注釈の継承が使用可能ではない 場合に、型の理論的な観点では安全であるものの、それでもなお問題が指摘される 1 つの状態があります。それは、スーパー・メソッドがパラメーターを @NonNull として宣言し、オーバーライドする側のメソッドが対応するパラメーターを (明示的な NULL 注釈によっても、適用可能な @NonNullByDefault によっても) 制約していない状態です。
この状況は安全です。スーパー宣言を参照するクライアントは null を回避するように強制される一方、オーバーライドする側の実装では、この特定のメソッドに指定がないため、この保証をまったく利用できないからです。
スーパータイプ内の宣言がすべてのオーバーライドにも適用されるよう意図している場合があるため、これは依然として誤解を招く可能性があります。
このため、コンパイラーには、 オーバーライドする側のメソッドで注釈が付けられていない「@NonNull」パラメーターというオプションが備わっています。
null が実際に許容されるべき場合には、@Nullable 注釈を追加して、スーパー・メソッドの @NonNull をオーバーライドすることをお勧めします。
前述の考慮事項を考慮に入れると、注釈を付ける対象となるコードが「レガシー」(つまり注釈なし) 型のサブタイプとして作成されている場合 (サード・パーティー・ライブラリーに由来する場合には変更できない)、さらに難しい事態となります。
最後のセクションを非常に注意深く読むと、@NonNull パラメーターが付いたメソッドによって「レガシー」メソッドがオーバーライドされる操作は承認できないことが分かります (スーパー・タイプを使用するクライアントは @NonNull の義務を「認識」しないため)。
この状況では、NULL 注釈は削除するしかありません (事後に注釈をライブラリーに追加する機能をサポートする計画がありますが、そのようなフィーチャーが使用可能になる時期や本当に使用できるようになるかについては、まだはっきりお答えできません。)。
@NonNullByDefault が指定されているパッケージ内に「レガシー」型のサブタイプがある場合には、注意が必要です。
注釈なしのスーパータイプを持つ型の場合、オーバーライドする側のメソッドに含まれるすべてのパラメーターに @Nullable のマークを付ける必要があります。パラメーター注釈を省略することさえ許可されていません。それを省略すると @NonNull パラメーターのように解釈されてしまうからです。それはその位置では禁止されています。
そのため、Eclipse Java コンパイラーでは NULL 特性デフォルトの取り消しがサポートされています。
メソッドまたは型に @NonNullByDefault(false) の注釈を付けると、このエレメントで適用されるデフォルトが取り消され、注釈なしのパラメーターは通常どおり指定なしとして解釈されます。
これでサブタイプは、不要な @Nullable 注釈を追加しなくても、やはり正しくなります。
class LegacyClass {
String enhance (String in) { // clients are not forced to pass nonnull.
return in.toUpperCase();
}
}
@NonNullByDefault
class MyClass extends LegacyClass {
// ... methods with @NonNull default ...
@Override
@NonNullByDefault(false)
String enhance(String in) { // would not be valid if @NonNullByDefault were effective here
return super.enhance(in);
}
}
NULL 注釈はメソッド・シグニチャーに適用される場合に最も効果を発揮します (通常、ローカル変数には注釈の必要自体がありませんが、注釈を付けられたコードと「レガシー」のコードの橋渡しをするために NULL 注釈を使用することもできます)。 こうした使用法の場合、NULL 注釈は、全体的なデータ・フローについてのステートメントを実行するためにプロシージャー内分析のチャンクに接続します。Eclipse Kepler 以降、NULL 注釈はフィールドにも適用可能になりました。ただし、若干異なる部分があります。
@NonNull とマークされたフィールドを考慮してみます。明らかにこの場合、対象フィールドに対する代入では、NULL ではないと分かっている値を提供する必要があります。
さらに、(値 null が依然として含まれている) 未初期化状態の非 NULL フィールドにはアクセスできないこともコンパイラーで検証できなければなりません。すべてのコンストラクターがこの規則に準拠していること (同様に静的フィールドにはイニシャライザーが必要) が検証可能な場合、プログラムはフィールドの間接参照が決して NullPointerException にならないという安全性のメリットを得られます。
@Nullable というマークが付けられているフィールドを考慮する場合、状況はより複雑です。
こうしたフィールドについては、危険があると常時見なす必要があり、NULL 可能なフィールドを扱うために推奨されている方法は、値を処理する前に必ずローカル変数に値を割り当てるというものです。
ローカル変数を使用すると、フロー分析によって、間接参照が NULL 検査によって十分に保護されているかどうかを正確に知ることができます。この一般的な規則に従うと、NULL 可能なフィールドの処理で問題が生じることはありません。
コードが NULL 可能フィールドの値を直接的に間接参照する場合、事態はより複雑になります。 問題となるのは、間接参照の前に実行される可能性があるコードの NULL 検査が、以下のいずれかにより簡単に無効になり得るという点です。
簡単に分かることですが、スレッド同期の分析もしないと (これはコンパイラーの機能の範疇ではありません)、NULL 可能フィールドに対する NULL 検査をしても、後続の間接参照が 100% 安全である保証は得られません。そのため、NULL 可能フィールドに対して並行アクセスが可能な場合、そのフィールドの値を絶対に 直接的に間接参照してはならず、代わりに必ず ローカル変数を使用する必要があります。 並行性が関係しない場合でも、残りの問題のせいで、完全な分析を行うという挑戦は、コンパイラーが通常処理できることに比べて一層難しいものとなります。
コンパイラーが別名割り当て、副次作用、および並行性の影響を十分に分析できない場合、Eclipse コンパイラーはフィールドのフロー分析をまったく行いません (その初期化に関する以外)。多くの開発者がこの制限 (コードが実際に安全でなければならないと開発者が感じる 場面では、ローカル変数を使用する必要がある) を制約的すぎると見なすと考えられることから、仮の妥協案として以下の新しいオプションが導入されました。
コンパイラーを、構文分析を実行するように構成できます。 これにより、次のような自明のパターンの大部分が検出されます。
@Nullable Object f;
void printChecked() {
if (this.f != null)
System.out.println(this.f.toString());
}
指定のオプションが有効である場合、コンパイラーは前述のコードにフラグを立てません。 この構文分析は決して「賢い」わけではないことを理解しておいてください。 検査と間接参照の間にコードが出現すると、コンパイラーは、残念なことに直前の NULL 検査の情報を「忘れて」しまいます。何らかの基準に照らして中間のコードが無害と思われるかどうかを判別しようとさえしません。 そのため、次のことを是非お勧めします。人間の目で見て NULL が絶対に生じないであろうと思われる状況であってもコンパイラーが NULL 可能フィールドの間接参照に安全ではないというフラグを立てる場合には、必ず、前述の示されたパターンに厳密に従うようにコードを書き換えるか、さらに賢明な方法としてローカル変数を使用して、構文分析では決して行えない、フロー分析の高性能な機能すべてを利用してください。
前述のように、契約による設計のスタイルの NULL 注釈を使用すると、作成する Java コードの品質をいくつかの面で向上させることができます。例えば、メソッド間のインターフェースで、どのパラメーター/戻りが NULL 値を受け入れてどれが受け入れないかが明白になります。 このようにすると、開発者にとって非常に重要な設計上の決定が反映されて、コンパイラーで検査することも可能になります。
さらに、このインターフェース仕様に基づいてプロシージャー内フロー分析を行うと、使用可能な情報を取り出して、より正確なエラー/警告を表示することができます。 注釈を使用しない場合、メソッドとの間でやり取りされる値の NULL 特性は不明であるため、NULL 分析では NULL の使用について何も報告されません。 API レベルの NULL 注釈を使用すると、ほとんどの値の NULL 特性がはっきり分かるため、コンパイラーによって認識されない NPE は格段に少なくなります。 それでもある程度の抜け穴が存在することは意識しておく必要があります。 例えば、未指定の値が分析に関係しているため、実行時に NPE が発生する可能性があるかどうかの完全な記述を作成できない場合があります。
NULL 注釈のサポートは、将来の拡張時に互換性を保つことを念頭に置いて設計されています。 この拡張は、Java 8 で導入された型注釈 (JSR 308) として Java 言語の一部となりました。 JDT では、NULL 型注釈という新しい概念を活用できます。
NULL 分析に基づく注釈のセマンティックの詳細については、以下に示す、コンパイラーが検査する規則と、規則の違反発生時に出るメッセージの説明を参照してください。
対応する設定ページでは、コンパイラーによって検査される個々の規則が次の各見出しに分類されています。
実際の実装が NULL 注釈の要求に違反しているような状況は、すべて指定違反として処理されます。
これが発生する典型的な状況は、値 (ローカル、引数、メソッド戻り) は @NonNull として指定されていても、実装時に実際には NULL 可能値が提供される場合です。
ここで、ある式が静的に値 NULL に評価されることが分かっている場合、または @Nullable 注釈を使用して宣言されている場合、この式は NULL 可能と見なされます。
2 番目の点として、このグループには、前の部分で説明したメソッド・オーバーライドの規則も含まれています。
ここで、スーパーメソッドは要求 (例えば、NULL は有効な引数であるという要求) を確立しますが、オーバーライドはこの要求を回避する方向に作用します (NULL が有効な引数ではない と想定するなど)。
既に説明したように、注釈なしの引数に @NonNull を付けて特殊化する操作さえも指定違反になってしまいます。
つまり、このような操作は、クライアントに (NULL を渡さないという) 制限を課す契約を示しますが、このスーパータイプを使用するクライアントは、この契約を見ることさえないため、何が期待されているのかさえも分かりません。
仕様違反として見なされる状況すべてを網羅したリストは、ここにあります。
このグループに含まれるエラーは決して無視すべきでないことを理解しておくことは重要です。これを無視すると、NULL 分析全体で誤った前提に基づいて分析が実行されてしまいます。
特にコンパイラーは、@NonNull 注釈付きの値を検出する箇所について、実行時に NULL が決して出現しないものとして処理します。
仕様違反についての規則が適正であるときに初めて、この推論が正しくなります。
そのため、この種の問題をエラーとして構成したままにしておくことを強くお勧めします。
この規則グループも、NULL 指定の順守を監視します。
しかし、ここで扱う値は、@Nullable として宣言 されていない (NULL 値自体でもない) 値で、かつ、実行パスのどこかで NULL が発生する可能性があるとプロシージャー内フロー分析により推測される 値です。
この状態は、注釈なしのローカル変数ではコンパイラーがフロー分析を使用して NULL の可否を推測する、という事実から発生します。 この分析が正確であると想定すると、問題が検出された場合に、その問題の重大度は、NULL 指定の直接の違反と同じになります。 そのため、ここでも、この問題をエラーとして構成したままにしておいて、これらのメッセージを無視しないことを強くお勧めします。
これらの問題に対して別個のグループを作成すると、2 つの目的の達成に役立ちます。 1 つは、フロー分析を利用して出された特定の問題を文書化するという目的、もう 1 つは、このフロー分析に (実装のバグのため) 欠陥がある可能性がある という事実を説明するという目的です。 認知されている実装バグの場合、例外的状況として、この種のエラー・メッセージを抑止しても問題ないという場合もあります。
静的分析の性質を考えると、フロー分析において、実行パスと値の特定の組み合わせが不可能であるという点を見落とす可能性があります。 例として、変数相関 を考慮しましょう。
String flatten(String[] inputs1, String[] inputs2) {
StringBuffer sb1 = null, sb2 = null;
int len = Math.min(inputs1.length, inputs2.length);
for (int i=0; i<len; i++) {
if (sb1 == null) {
sb1 = new StringBuffer();
sb2 = new StringBuffer();
}
sb1.append(inputs1[i]);
sb2.append(inputs2[i]); // warning here
}
if (sb1 != null) return sb1.append(sb2).toString();
return "";
}
コンパイラーは、sb2.append(..) の呼び出しにおける潜在的な NULL ポインター・アクセスを報告します。
一方、人間の読者は、実際の危険はないと理解します。なぜなら、sb1 と sb2 は、実際には両方の変数が Null になるか両方が非 NULL になるかのいずれかになるように相関しているためです。
問題の行において sb1 が NULL 以外であることが分かっているため、sb2 も NULL ではありません。
そのような相関分析が Eclipse Java コンパイラーの能力を超えている理由をここでは詳しく取り上げませんが、この分析は、定理証明機能としての十分の能力を備えていないため、問題を消極的に判断して報告するようになっていることは覚えておいてください。さらに高度な分析では、こうした問題の一部は誤った警告と見なされる可能性があります。
フロー分析を活用するには、作成したコードの結果をコンパイラーが理解できるように、多少の工夫をすることをお勧めします。
この工夫は、if (sb1 == null) を 2 つの別個の if に分割してローカル変数ごとに 1 つずつ使用するという簡単なものであるかもしれません。これだけのほんのわずかな労力で、コンパイラーが状況を正確に理解してコードを正確に検査できるようになるという収穫があります。
このトピックの詳しい説明を以下に記載します。
この問題のグループは、次の類推に基づいています。 つまり、Java 5 の総称型を使用するプログラムで Java 5 より前のライブラリーを呼び出すと、具体的な型引数を指定しないで総称型を適用してしまい、raw 型が露出してしまう可能性があるということです。 総称型を使用するプログラムにそのような値を適合させるため、コンパイラーは、コード内のクライアント部分で必要な形式の型引数が指定されたと想定して、暗黙変換 を追加することがあります。 コンパイラーは、そのような変換の使用に関する警告を発行し、ライブラリーの処理方法は正しいと想定して型の検査を続行します。 ライブラリー・メソッドの、注釈なしの戻りの型も、まったく同様に、「raw」型または「レガシー」型と見なすことができます。 この場合もまた、暗黙変換 のときには、期待する仕様になっているという楽観的な想定をすることができます。 ここでも警告が出され、分析は、ライブラリーの処理方法は正しいと想定して引き続き行われます。
理論的には、そのような暗黙変換が必要になることも、仕様違反があることを示しています。 ただしこの場合、作成したコードで必要な仕様を違反しているのは、サード・パーティーのコードである可能性があります。 あるいは、サード・パーティーのコードが契約を満たしている (と確信している) としても、そのように宣言していないだけかもしれません (そのコードで NULL 注釈を使用していないため)。 そのような状況では、組織上の 理由で、問題を完全に修正することは不可能かもしれません。
@SuppressWarnings("null")
@NonNull Foo foo = Library.getFoo(); // implicit conversion
foo.bar();
上記のコード・スニペットでは、Library.getFoo() が NULL 注釈を指定せずに Foo を返すと想定しています。
この戻り値を注釈付きプログラムに統合するときには、@NonNull のローカル変数に割り当てることができます。このようにすると、未検査型変換に関して警告がトリガーされます。
対応する SuppressWarnings("null") をこの宣言に追加することにより、内在する危険を認知していることを示し、ライブラリーが実際に期待どおりに作動することを検証する責任を受け入れます。
フロー分析で値が実際に非 NULL であることを確認できない場合、@NonNull の注釈を付けた新しいローカル・スコープ変数を追加するというのが常に最も単純な方法です。
その後、このローカルに割り当てられた値が実行時に決して NULL にならないと確信したら、次のようなヘルパー・メソッドを使用できます。
static @NonNull <T> T assertNonNull(@Nullable T value, @Nullable String msg) {
if (value == null) throw new AssertionError(msg);
return value;
}
@NonNull MyType foo() {
if (isInitialized()) {
MyType couldBeNull = getObjectOrNull();
@NonNull MyType theValue = assertNonNull(couldBeNull,
"value should not be null because application " +
"is fully initialized at this point.");
return theValue;
}
return new MyTypeImpl();
}
上記の assertNonNull() メソッドを使用することにより、実行時にこのアサーションが常に成り立つようにするという責任を受け入れることになります。
それを受け入れたくない場合でも、注釈付きのローカル変数を使用すると、特定の位置に NULL が入り込む可能性が分析によって検出される場所と理由を、特定の範囲に絞ることができます。
JDT バージョン 3.8.0 のリリース時点では、NULL 注釈を採用するためのアドバイスの収集はまだ進行中の作業です。 そのため、この情報は現在、Eclipse wiki で保守されています。