web-dev-qa-db-ja.com

@Nonnullで注釈が付けられたパラメーターがnullかどうかを確認しますか?

FindBugsの使用を開始し、パラメーターに適切に @Nonnull の注釈を付けました。サイクルの早い段階でバグを指摘することは非常に効果的です。これまで、Guavaのnullを使用してcheckNotNullのこれらの引数をチェックしてきましたが、nullをエッジでのみチェックすることをお勧めします。つまり、nullをチェックせずに値を取得できる場所、たとえば、SOAPリクエスト。

// service layer accessible from outside
public Person createPerson(@CheckForNull String name) {
    return new Person(Preconditions.checkNotNull(name));
}

...

// internal constructor accessed only by the service layer
public Person(@Nonnull String name) {
    this.name = Preconditions.checkNotNull(name);  // remove this check?
}

@Nonnullnullの値自体をブロックしないことを理解しています。

ただし、FindBugsはマークされていないフィールドからマークされた@Nonnullに値が転送される場所を指し示すため、nullのこれらの値を確認する必要なしに、これらのケースをキャッチするためにそれを信頼することはできません。彼らはシステムのどこにでも渡りますか?ツールを信頼し、これらの冗長なチェックを避けたいと思ったことはありませんか?

ボトムライン:以下の2番目のnullチェックを削除しても安全と思われますが、それは悪い習慣ですか?

この質問は多分 nullを期待していない場合、nullをチェックする必要があります に似ていますが、@Nonnullアノテーションに関して具体的に質問しています。

19
David Harkness

FindBugを信頼しない場合は、アサーションを使用することもできます。これにより、ユーザーMSalterによって言及された問題を回避しながら、チェックを行うことができます。もちろん、このようなフェイルファストアプローチが実現可能でない場合、つまり、例外をキャッチする必要がある場合、このアプローチは適用できない場合があります。

そして、それが悪い習慣であるかどうかという質問にさらに答えること。まあ、これは議論の余地がありますが、私はそうは思いません。私は、このFindBugアノテーションを、契約の原則による設計に従った軽い仕様と見なしています。

契約による設計では、メソッドとその呼び出し元との間の契約を確立します。コントラクトは、メソッドを呼び出すときに呼び出し元が満たすことに同意する前提条件と、その前提条件が満たされた場合に実行後にメソッドによって満たされる事後条件で構成されます。

この開発方法の利点の1つは、いわゆる防御的プログラミングスタイル(すべての無効なパラメーター値を明示的にチェックするなど)を回避できることです。代わりに、コントラクトに依存し、冗長なチェックを回避して、パフォーマンスと読みやすさを向上させることができます。

コントラクトは、実行時アサーションチェックに使用できます。これは、コントラクトが壊れた場合にプログラムを失敗させ、エラーの原因を特定する手がかりとなる、前述のフェイルファーストの原則に従います。 (失敗した前提条件は、呼び出し元が何か間違ったことを意味し、失敗した事後条件は、指定されたメソッドの実装エラーを示します)

さらに、コントラクトは静的分析に使用でき、ソースコードを実際に実行せずにソースコードに関する結論を引き出そうとします。

@nonnullアノテーションは、FindBugsツールによる静的分析に使用される前提条件と見なすことができます。ランタイムアサーションチェックなどのアプローチ、つまりフェイルファースト戦略を好む場合は、組み込みJavaとしてアサーションステートメントを使用することを検討する必要があります。または、Javaモデリング言語(JML))などの動作インターフェース仕様言語を使用して、より高度な仕様戦略に適応することもできます。

JMLは、Javaで、仕様が特殊なJavaコメントに埋め込まれています。このコメントの拡張です。このアプローチの利点は、実装の詳細ではなく仕様のみに依存し、前述のランタイムアサーションチェックツール、ユニットテストの自動生成、ドキュメントなど、仕様を利用するさまざまなツールを使用する開発アプローチ。

@nonnullが(軽い)コントラクトであるという私の見解を共有する場合、追加のチェックを追加しないのが一般的な慣習です。

6
FabianB

さて、あなたが書いていない理由を考えてください

this.name = Preconditions.checkNotNull(name);  // Might be necessary
that.name = Preconditions.checkNotNull(this.name);  // Who knows?

プログラミングは黒魔術ではありません。変数が突然Nullになることはありません。変数がNullではなく、変更されていないことがわかっている場合は、notを確認します。

チェックした場合、将来の一部のプログラマー(おそらくあなた)は、そのチェックが存在する理由を見つけるのに多くの時間を費やすでしょう。結局、小切手は理由があるはずだから、見落としは何ですか?

4
MSalters