どの@NotNull Javaアノテーションを使用すればよいですか? 質問する

どの@NotNull Javaアノテーションを使用すればよいですか? 質問する

私は、コードをより読みやすくし、IDE コード検査や静的コード分析 (FindBugs や Sonar) などのツールを使用して NullPointerExceptions を回避したいと考えています。多くのツールは、互いの//@NotNullアノテーションと互換性がないようです。コードにそれらすべてをリストすると、読みにくくなります。どれが「最適」か、何かアドバイスはありますか? 以下は、私が見つけた同等のアノテーションのリストです。@NonNull@Nonnull

ベストアンサー1

以来JSR305(その目標は@NonNullと を標準化することだった@Nullable) は数年間休眠状態にあるため、残念ながら良い答えはありません。私たちにできるのは実用的な解決策を見つけることだけであり、私の解決策は次のとおりです。

構文

純粋にスタイルの観点から、Java 自体以外の IDE、フレームワーク、またはツールキットへの参照は避けたいと思います。

これにより、次のことが除外されます:

  • android.support.annotation
  • edu.umd.cs.findbugs.annotations
  • org.eclipse.jdt.annotation
  • org.jetbrains.annotations
  • org.checkerframework.checker.nullness.qual
  • lombok.NonNull

javax.validation.constraintsそうなると、 かのどちらかしか残っていませんjavax.annotation。前者は JEE に付属しています。これが よりも優れているかjavax.annotationどうかは議論の余地があります。後者は最終的には JSE に付属するか、まったく付属しない可能性があります。私は個人的に の方が好きですjavax.annotation。なぜなら、JEE への依存は嫌だからです。

これで、

javax.annotation

これは最も短いものでもあります。

これより優れた構文は 1 つだけです: 。過去にjava.annotation.Nullable他のパッケージが から に移行したようにjavax、 javax.annotation は正しい方向への一歩となるでしょう。java

実装

基本的にすべてが同じ単純な実装になっていることを期待していましたが、詳細な分析により、そうではないことがわかりました。

まず類似点から:

注釈@NonNullにはすべて次の行があります

public @interface NonNull {}

を除いて

  • org.jetbrains.annotationsそれを呼び出し@NotNull、簡単な実装を持つ
  • javax.annotation実装期間が長い
  • javax.validation.constraintsこれもそれを呼び出し@NotNull、実装している

注釈@Nullable にはすべて次の行があります

public @interface Nullable {}

ただし、(再び)そのorg.jetbrains.annotations簡単な実装を除きます。

相違点については、次のとおりです。

印象的なのは

  • javax.annotation
  • javax.validation.constraints
  • org.checkerframework.checker.nullness.qual

すべて実行時注釈(@Retention(RUNTIME))を持ちますが、

  • android.support.annotation
  • edu.umd.cs.findbugs.annotations
  • org.eclipse.jdt.annotation
  • org.jetbrains.annotations

コンパイル時のみです ( @Retention(CLASS))。

記載の通りこのSOの答えランタイム アノテーションの影響は想像するよりも小さいですが、コンパイル時のチェックに加えて、ツールがランタイム チェックを実行できるようにするという利点があります。

もう 1 つの重要な違いは、コード内でアノテーションを使用できる場所です。2 つの異なるアプローチがあります。一部のパッケージでは、JLS 9.6.4.1 スタイルのコンテキストを使用します。次の表に概要を示します。

パッケージ 分野 方法 パラメータ ローカル変数
Android サポートの注釈 ✔️ ✔️ ✔️
edu.umd.cs.findbugs.注釈 ✔️ ✔️ ✔️ ✔️
org.jetbrains.annotation ✔️ ✔️ ✔️ ✔️
ロンボク ✔️ ✔️ ✔️ ✔️
javax.validation.constraints ✔️ ✔️ ✔️

org.eclipse.jdt.annotation定義されたコンテキストを使用しjavax.annotationますorg.checkerframework.checker.nullness.qualJLS4.11 翻訳、それは正しいやり方だと私は思います。

これで、

  • javax.annotation
  • org.checkerframework.checker.nullness.qual

このラウンドでは。

コード

あなた自身でさらに詳細を比較できるように、以下に各注釈のコードをリストします。比較を容易にするために、コメント、インポート、注釈を削除しました。( Android パッケージのクラスを除いて@Documentedすべて削除しました)。行とフィールドの順序を変更し、資格を正規化しました。@Documented@Target

package android.support.annotation;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER})
public @interface NonNull {}

package edu.umd.cs.findbugs.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface NonNull {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NotNull {String value() default "";}

package javax.annotation;
@TypeQualifier
@Retention(RUNTIME)
public @interface Nonnull {
    When when() default When.ALWAYS;
    static class Checker implements TypeQualifierValidator<Nonnull> {
        public When forConstantValue(Nonnull qualifierqualifierArgument,
                Object value) {
            if (value == null)
                return When.NEVER;
            return When.ALWAYS;
        }
    }
}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf(MonotonicNonNull.class)
@ImplicitFor(
    types = {
        TypeKind.PACKAGE,
        TypeKind.INT,
        TypeKind.BOOLEAN,
        TypeKind.CHAR,
        TypeKind.DOUBLE,
        TypeKind.FLOAT,
        TypeKind.LONG,
        TypeKind.SHORT,
        TypeKind.BYTE
    },
    literals = {LiteralKind.STRING}
)
@DefaultQualifierInHierarchy
@DefaultFor({TypeUseLocation.EXCEPTION_PARAMETER})
@DefaultInUncheckedCodeFor({TypeUseLocation.PARAMETER, TypeUseLocation.LOWER_BOUND})
public @interface NonNull {}

完全を期すために、@Nullable実装を以下に示します。

package android.support.annotation;
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {}

package edu.umd.cs.findbugs.annotations;
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
@Retention(CLASS)
public @interface Nullable {}

package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface Nullable {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface Nullable {String value() default "";}

package javax.annotation;
@TypeQualifierNickname
@Nonnull(when = When.UNKNOWN)
@Retention(RUNTIME)
public @interface Nullable {}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf({})
@ImplicitFor(
    literals = {LiteralKind.NULL},
    typeNames = {java.lang.Void.class}
)
@DefaultInUncheckedCodeFor({TypeUseLocation.RETURN, TypeUseLocation.UPPER_BOUND})
public @interface Nullable {}

次の 2 つのパッケージには がない@Nullableため、別々にリストします。Lombok には非常に退屈な があります@NonNull。 の はjavax.validation.constraints実際@NonNullには であり@NotNull、実装が長めです。

package lombok;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package javax.validation.constraints;
@Retention(RUNTIME)
@Target({ FIELD, METHOD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Constraint(validatedBy = {})
public @interface NotNull {
    String message() default "{javax.validation.constraints.NotNull.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default {};
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        NotNull[] value();
    }
}

サポート

私の経験からすると、javax.annotation少なくとも Eclipse と Checker Framework ではすぐにサポートされます。

まとめ

java.annotation私の理想的な注釈は、Checker Framework 実装を使用した構文です。

Checker Frameworkを使用しない場合は、javax.annotationJSR-305) が今のところ依然として最善の選択肢です。

Checker Framework を購入する場合は、 を使用してくださいorg.checkerframework.checker.nullness.qual


出典

  • android.support.annotationからandroid-5.1.1_r1.jar
  • edu.umd.cs.findbugs.annotationsからfindbugs-annotations-1.0.0.jar
  • org.eclipse.jdt.annotationからorg.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
  • org.jetbrains.annotationsからjetbrains-annotations-13.0.jar
  • javax.annotationからgwt-dev-2.5.1-sources.jar
  • org.checkerframework.checker.nullness.qualからchecker-framework-2.1.9.zip
  • lomboklombokコミットからf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
  • javax.validation.constraintsからvalidation-api-1.0.0.GA-sources.jar

おすすめ記事