私は、コードをより読みやすくし、IDE コード検査や静的コード分析 (FindBugs や Sonar) などのツールを使用して NullPointerExceptions を回避したいと考えています。多くのツールは、互いの//@NotNull
アノテーションと互換性がないようです。コードにそれらすべてをリストすると、読みにくくなります。どれが「最適」か、何かアドバイスはありますか? 以下は、私が見つけた同等のアノテーションのリストです。@NonNull
@Nonnull
javax.validation.constraints.NotNull
静的分析ではなく、実行時検証用に作成されました。
ドキュメンテーションedu.umd.cs.findbugs.annotations.NonNull
によって使われたバグを見つける(死んだプロジェクト)およびその後継スポットバグ静的解析とSonar(現在ソナーキューブ)
FindBugs ドキュメント、SpotBugs ドキュメントjavax.annotation.Nonnull
これはFindBugsでも機能するかもしれないが、JSR-305非アクティブです。(参照:JSR 305 のステータスはどうなっていますか?) ソースorg.jetbrains.annotations.NotNull
IntelliJ IDEA IDE によって静的解析に使用されます。
ドキュメンテーションlombok.NonNull
コード生成を制御するために使用プロジェクト ロンボク標準がないのでプレースホルダー注釈。
ソース、ドキュメンテーションandroidx.annotation.NonNull
Android でマーカー注釈が利用可能になりました。注釈パッケージによって提供されます。
ドキュメンテーションorg.eclipse.jdt.annotation.NonNull
Eclipse による静的コード解析に使用される
ドキュメンテーション
ベストアンサー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.qual
JLS4.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.annotation
(JSR-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
lombok
lombok
コミットからf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
からvalidation-api-1.0.0.GA-sources.jar