web-dev-qa-db-ja.com

@Nullableおよび@Nonnullアノテーションをより効果的に使用する方法は?

@Nullableおよび@Nonnull注釈couldNullPointerExceptionsを防ぐのに役立ちますが、あまり伝播しません。

  • これらの注釈の有効性は、1レベルの間接参照の後に完全に低下するため、追加するのが少数である場合、それらはあまり伝播しません。
  • これらのアノテーションは十分に実施されていないため、@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        
    }
}

これらの注釈をより厳密に強制したり、さらに伝播したりする方法はありますか?

105
Mike Rylander

簡単な答え:これらの注釈は、IDEが潜在的にヌルポインターエラーを警告する場合にのみ役立つと思います。

「コードのクリーン化」の本で述べたように、パブリックメソッドのパラメーターを確認し、不変条件のチェックも避ける必要があります。

もう1つの良いヒントは、決してnull値を返さないことですが、代わりに Null Object Pattern を使用します。

53
Pedro Boechat

IDEの横に、nullがnullでないと予想される場所を渡すというヒントを与えて、さらに利点があります。

  • 静的コード分析ツールは、IDEと同じものをテストできます(例:FindBugs)
  • AOPを使用してこのアサーションを確認できます

そのため、より保守しやすく(nullチェックは不要)、エラーが発生しにくいコードを作成するのに役立ちます。

22
Uwe Plonus

コンプライアンス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について警告するオプションがあります。型システム。

11

この元の質問は、@ NonNullが使用されていても、実行時のNULLポインターチェックがまだ必要であるという一般的な推奨事項を間接的に指していると思います。次のリンクを参照してください。

Java 8の新しい型注釈

上記のブログでは、次のことが推奨されています。

オプションの型注釈は実行時検証の代替ではありません型注釈の前は、null許容性や範囲などを記述する主な場所はjavadocでした。 Typeアノテーションを使用すると、この通信はコンパイル時の検証のためにバイトコードに入ります。コードは実行時検証を実行する必要があります。

10
jonathanzh

注釈は「あまり伝播しない」ことに同意します。しかし、プログラマー側には間違いがあります。

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);
    }
6
Andres

私のプロジェクトで行っていることは、「一定の条件と例外」コード検査で次のオプションをアクティブにすることです。
nullを返す可能性のあるメソッドの@Nullableアノテーションを提案し、非アノテーション付きパラメーターに渡されたnull可能値を報告するInspections

有効にすると、注釈のないすべてのパラメーターは非ヌルとして扱われるため、間接呼び出しでも警告が表示されます。

clazz.indirectPathToA(null); 

より強力なチェックを行うには、Checker Frameworkが適切な選択です(このNice tutorial を参照してください)。
:まだ使用していないため、Jackコンパイラに問題がある可能性があります: this bugreport を参照してください=

4
TmTron

Javaでは、 Guava's Optional type を使用します。実際の型であるため、コンパイラはその使用について保証されます。これをバイパスしてNullPointerExceptionを取得するのは簡単ですが、少なくともメソッドのシグネチャは、引数として何を期待するのか、または何を返すのかを明確に伝えます。

3
Ionuț G. Stan

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

3
Mike Rylander