@Nullable
および@Nonnull
注釈couldはNullPointerException
sを防ぐのに役立ちますが、あまり伝播しません。
@Nonnull
でマークされた値がnullではないと想定し、その結果nullチェックを実行しない危険があります。以下のコードにより、@Nonnull
でマークされたパラメーターは、null
になり、苦情は発生しません。実行時にNullPointerException
をスローします。
public class Clazz {
public static void main(String[] args){
Clazz clazz = new Clazz();
// this line raises a complaint with the IDE (IntelliJ 11)
clazz.directPathToA(null);
// this line does not
clazz.indirectPathToA(null);
}
public void indirectPathToA(Integer y){
directPathToA(y);
}
public void directPathToA(@Nonnull Integer x){
x.toString(); // do stuff to x
}
}
これらの注釈をより厳密に強制したり、さらに伝播したりする方法はありますか?
簡単な答え:これらの注釈は、IDEが潜在的にヌルポインターエラーを警告する場合にのみ役立つと思います。
「コードのクリーン化」の本で述べたように、パブリックメソッドのパラメーターを確認し、不変条件のチェックも避ける必要があります。
もう1つの良いヒントは、決してnull値を返さないことですが、代わりに Null Object Pattern を使用します。
IDEの横に、null
がnullでないと予想される場所を渡すというヒントを与えて、さらに利点があります。
そのため、より保守しやすく(null
チェックは不要)、エラーが発生しにくいコードを作成するのに役立ちます。
コンプライアンス1.8でEclipseの元の例をコンパイルし、注釈ベースのヌル分析を有効にすると、次の警告が表示されます。
directPathToA(y);
^
Null type safety (type annotations): The expression of type 'Integer' needs unchecked conversion to conform to '@NonNull Integer'
この警告は、生のタイプを使用して生成コードとレガシーコードを混在させる場合に得られる警告(「未チェックの変換」)に類似しています。ここにもまったく同じ状況があります。メソッドindirectPathToA()
には、nullコントラクトを指定しないという点で「レガシー」シグネチャがあります。ツールはこれを簡単に報告できるので、nullアノテーションを伝播する必要があるがまだそうではない路地を追いかけます。
そして、賢い@NonNullByDefault
を使用する場合、毎回これを言う必要さえありません。
つまり、null注釈が「非常に遠くまで伝播する」かどうかは、使用するツールと、ツールによって発行されるすべての警告にどの程度厳密に対応するかによって決まります。 TYPE_USE null annotations を使用すると、最終的に、ツールですべてのプログラムで発生する可能性のあるNPEについて警告するオプションがあります。型システム。
この元の質問は、@ NonNullが使用されていても、実行時のNULLポインターチェックがまだ必要であるという一般的な推奨事項を間接的に指していると思います。次のリンクを参照してください。
上記のブログでは、次のことが推奨されています。
オプションの型注釈は実行時検証の代替ではありません型注釈の前は、null許容性や範囲などを記述する主な場所はjavadocでした。 Typeアノテーションを使用すると、この通信はコンパイル時の検証のためにバイトコードに入ります。コードは実行時検証を実行する必要があります。
注釈は「あまり伝播しない」ことに同意します。しかし、プログラマー側には間違いがあります。
Nonnull
注釈をドキュメントとして理解しています。次のメソッドは、(前提条件として)null以外の引数x
が必要であることを表します。
public void directPathToA(@Nonnull Integer x){
x.toString(); // do stuff to x
}
次のコードスニペットにはバグが含まれています。このメソッドは、y
がNULLでないことを強制せずにdirectPathToA()
を呼び出します(つまり、呼び出されたメソッドの前提条件を保証しません)。可能性の1つは、Nonnull
注釈をindirectPathToA()
に追加することです(前提条件の伝搬)。可能性2は、indirectPathToA()
のy
のnullityをチェックし、y
がnullのときにdirectPathToA()
の呼び出しを避けることです。
public void indirectPathToA(Integer y){
directPathToA(y);
}
私のプロジェクトで行っていることは、「一定の条件と例外」コード検査で次のオプションをアクティブにすることです。
nullを返す可能性のあるメソッドの@Nullableアノテーションを提案し、非アノテーション付きパラメーターに渡されたnull可能値を報告する
有効にすると、注釈のないすべてのパラメーターは非ヌルとして扱われるため、間接呼び出しでも警告が表示されます。
clazz.indirectPathToA(null);
より強力なチェックを行うには、Checker Frameworkが適切な選択です(このNice tutorial を参照してください)。
注:まだ使用していないため、Jackコンパイラに問題がある可能性があります: this bugreport を参照してください=
Javaでは、 Guava's Optional type を使用します。実際の型であるため、コンパイラはその使用について保証されます。これをバイパスしてNullPointerException
を取得するのは簡単ですが、少なくともメソッドのシグネチャは、引数として何を期待するのか、または何を返すのかを明確に伝えます。
Kotlinを使用する場合、コンパイラでこれらのnullabilityアノテーションをサポートし、null以外の引数を必要とするJavaメソッドにnullを渡すことを防ぎます。この質問はもともとJavaを対象としていましたが、これらのJavaアノテーションを具体的に対象にしているため、このKotlin機能について言及します質問は"でしたこれらの注釈を作成しますより厳密に実施および/またはさらに伝播しますか? "この機能はこれらの注釈をより厳密に実施します。
@NotNull
注釈を使用するJavaクラス
public class MyJavaClazz {
public void foo(@NotNull String myString) {
// will result in an NPE if myString is null
myString.hashCode();
}
}
Javaクラスを呼び出し、@ NotNullアノテーションが付けられた引数にnullを渡すKotlinクラス
class MyKotlinClazz {
fun foo() {
MyJavaClazz().foo(null)
}
}
@NotNull
注釈を強制するKotlinコンパイラエラー。
Error:(5, 27) Kotlin: Null can not be a value of a non-null type String
参照: http://kotlinlang.org/docs/reference/Java-interop.html#nullability-annotations