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


998

NullPointerExceptionsを回避するために、コードを読みやすくするだけでなく、IDEコードインスペクションや静的コード分析(FindBugsおよびSonar)などのツールを使用したいと考えています。ツールの多くはお互いの@NotNull/ @NonNull/ @Nonnullアノテーションと互換性がないように見え、すべてのツールを私のコードにリストすると読みにくくなります。どれが「最高」であるかの提案はありますか?これが私が見つけた同等の注釈のリストです:


203
Apacheは、「共通の」注釈とそれを他の注釈に変換できるツールを発明する必要があります。規格が多すぎるという問題の解決策は、新しい規格を発明することです。
2011

6
apacheが新しい「共通」を発明した場合、@評判が悪く、56のバージョンがあり、他のプロジェクトと重複しています。そして、それはとにかく標準ではありません(標準!=広く使われています)。本当に標準的なもの、javax?。*を使用する方が良いでしょう。ところで、「あまりにも多くの基準は、」これらの例ではありません、私はちょうど1か2を参照
ymajoros

6
javax.annotation.Nonnullは、findbugs(テストしたばかり)でも機能します。これは、私がそれを使用する説得力のある理由です。
Nicolas C

20
単に@NotNullと書くと、を指しcom.sun.istack.internal.NotNullます。OMG ...
トーマスウェラー

3
@MozartBrocchini-オプションは、以前にNullObjectsを使用したことがある場合に役立ちます。ただし、実行時の\ @NotNullアノテーションと同じ目的には実際には対応しておらず、面倒なアンラップを導入しています。
Dave、

回答:


205

以来JSR 305(その目標は標準化した@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.constraintsjavax.annotation。前者はJEEに付属しています。これがjavax.annotationJSEに最終的に含まれるか、まったく含まれないかのどちらかであるかどうかは、議論の余地があります。個人的javax.annotationには、JEEの依存関係が気に入らないので、好きです。

これは私たちに残します

javax.annotation

これも最短のものです。

さらに優れている構文は1つだけですjava.annotation.Nullable。他のパッケージが卒業したようjavaxjava、過去に、javax.annotationは正しい方向への第一歩になります。

実装

基本的に同じ簡単な実装であることを期待していましたが、詳細な分析により、これは正しくないことがわかりました。

最初に類似点について:

@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スタイルのコンテキストを使用します。次の表に概要を示します。

                                FIELD METHOD PARAMETER LOCAL_VARIABLE 
android.support.annotation XXX   
edu.umd.cs.findbugs.annotations XXXX
org.jetbrains.annotation XXXX
ロンボクXXXX
javax.validation.constraints XXX   

org.eclipse.jdt.annotationjavax.annotationそしてorg.checkerframework.checker.nullness.qualJLS 4.11で定義されたコンテキストを使用します。これは、私の意見では正しい方法です。

これは私たちに残します

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

このラウンドで。

コード

詳細を自分で比較できるように、すべての注釈のコードを以下に示します。比較を簡単にするために、コメント、インポート、@Documented注釈を削除しました。(@DocumentedAndroidパッケージのクラスを除いて、すべてがありました)。行と@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、個別にリストします。ロンボクはかなり退屈@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とチェッカーフレームワークはそのまま使用できます。

概要

私の理想的な注釈は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

7
の欠点javax.annotationは、それがa)死んだJSRに基づいていること、b)アノテーションを提供し、維持されているだけの成果物を見つけるのが難しいことです。findbugsからのものではありません。search.maven.org
robinst

18
別のポイントjavax.annotationは、他のモジュールもそのパッケージ(jax-ws)にクラスを提供するため、Java 9で問題が発生することです。
robinst 2017

10
@kevinarpe:Findbugsプロジェクトは死んでおり、後継プロジェクトのSpotbugsがこれらの注釈を削除しています:github.com/spotbugs/spotbugs/pull/180
robinst

4
標準化されたはずのJSR 305はjavax.annotation.NonNullスペックリードがAWOLになったため、完成しませんでした。オラクルの決定とは何の関係もありませんでした。
マークラインホルト2018

5
jsr305.jarを使用しないもう1つの理由は、それが明らかにOracle Javaバイナリライセンスに違反していることです。github.com
Flow

91

ヌルチェッカーなどの欠陥チェッカーを実装するために使用される型注釈(JSR-308)の実装であるチェッカーフレームワークがとても気に入っています。私は実際に他の人に比較を提供することを試みたことはありませんが、この実装に満足しています。

私はソフトウェアを提供するグループとは関係ありませんが、私はファンです。

このシステムについて私が気に入っている4つのこと:

  1. nullの欠陥チェッカー(@Nullable)がありますが、不変性内部(およびその他)の欠陥チェッカーもあります。最初の1つ(nullness)を使用し、2番目の1つ(不変性/ IGJ)を使用しようとしています。3番目のものを試していますが、長期的に使用するかどうかはまだわかりません。他のチェッカーの一般的な有用性についてはまだ確信がありませんが、フレームワーク自体がさまざまな追加のアノテーションとチェッカーを実装するためのシステムであることを知ってうれしいです。

  2. null 値チェックデフォルト設定は適切に機能します。ローカル以外の非null(NNEL)。基本的に、これはデフォルトでチェッカーがローカル変数を除くすべて(インスタンス変数、メソッドパラメーター、ジェネリック型など)を、デフォルトで@NonNull型であるかのように処理することを意味します。ドキュメントごと:

    NNELのデフォルトでは、コード内の明示的な注釈の数が最小になります。

    NNELが機能しない場合は、クラスまたはメソッドに別のデフォルトを設定できます。

  3. このフレームワークを使用すると、注釈をコメントで囲むことにより、フレームワークへの依存関係を作成せずにを使用できます/*@Nullable*/。ライブラリまたは共有コードに注釈を付けてチェックできますが、フレームワークを使用しない別のプロジェクトでそのライブラリ/共有コードを引き続き使用できるので、これは素晴らしいです。これは素晴らしい機能です。今ではすべてのプロジェクトでChecker Frameworkを有効にする傾向がありますが、私はそれを使用することに慣れてきました。

  4. フレームワークには、スタブファイルを使用してnullがまだアノテーションされていないAPIアノテーション付ける方法があります。


3
すばらしいようですが、使いたいのですが使えません。なぜGPLなのか?代わりに、それはLGPLではないでしょうか?
Burkhard

13
FAQによると:「より寛容なMITライセンスは、アノテーションなど、独自のプログラムに含めたいコードに適用されます。」
seanf 2013

1
リンクは現在壊れています。しかし、Checker Frameworkの使用に関するアドバイスは+1です。
Paul Wagland

1
不変性チェッカーが最新リリースで削除されているのは残念です。
フランクリンユー

1
チェッカーフレームワークは、Oracle Javaチュートリアルでも推奨されています
Quazi Irfan、2018

55

IntelliJを使用します。これは、NPEを生成する可能性があるものにフラグを付けるIntelliJに主に関心があるためです。JDKに標準のアノテーションがないとイライラすることに同意します。それを追加するという話があります。それはJava 7になるかもしれません。その場合、もう1つ選択できます!


68
:更新:あなたはのIntelliJの注釈、それ以上に限定されるものではないので、IntelliJのは、今、コードの強調表示のための上記の注釈のすべてのサポートされていblogs.jetbrains.com/idea/2011/03/...
ダニエルAlexiuc

31
Eclipse Junoも同様です。
jFrenetic

5
javax.annotation.Nonnullより広く受け入れられていますね。
マーティン

1
@DanielAlexiucしかし、残念なことに、ランタイムチェックにそれらを使用しないので、JetBrainsのものを使用することには依然として利点があります...
Trejkaz

4
@Trejkaz 2016.3以降、これらすべてのランタイムチェックが作成されます。
Karol S

32

Java 7の機能リストによると、JSR-308タイプのアノテーションはJava 8に委ねられています。JSR-305アノテーションについても言及されていません。

最新のJSR-308ドラフトの付録に、JSR-305の状態に関する情報が少しあります。これには、JSR-305アノテーションが放棄されているように見えるという観察が含まれます。JSR-305ページでも「非アクティブ」と表示されています。

それまでの間、実用的な答えは、最も広く使用されているツールでサポートされているアノテーションタイプを使用することです。


実際、JSR-308は注釈のタイプ/クラスを定義しておらず、範囲外と考えているようです。(そして、JSR-305の存在を考えると、それらは正しいです)。

ただし、JSR-308が本当にJava 8になったように見える場合でも、JSR-305への関心が復活したとしても、私は驚かないでしょう。AFAIK、JSR-305チームは正式に彼らの仕事を放棄していません。彼らは2年間以上静かでした。

興味深いのは、Bill Pugh(JSR-305の技術リーダー)がFindBugsを支えている人物の1人であることです。


4
@pst-現在のスケジュールは、Java 8が2013年9月に一般リリースされる予定です-infoq.com/news/2012/04/jdk-8-milestone-release-dates
Stephen C

2
それは今や2014年3月に落ちています-openjdk.java.net/projects/jdk8。JSR 308はビルドM7に含まれています(「104-Java型に関する注釈」を参照)。
スティーブンC

28

Androidプロジェクトではandroid.support.annotation.NonNull、およびを使用する必要がありandroid.support.annotation.Nullableます。これらおよびその他の役立つAndroid固有のアノテーションは、サポートライブラリで入手できます。

http://tools.android.com/tech-docs/support-annotationsから:

サポートライブラリ自体にもこれらのアノテーションが付いているため、サポートライブラリのユーザーとして、Android Studioはすでにコードをチェックし、これらのアノテーションに基づいて潜在的な問題にフラグを立てます。


3
その推奨事項を正当化することは有用です。
アプリコット

2
tools.android.com/tech-docs/support-annotations「サポートライブラリ自体にもこれらのアノテーションが付けられているため、サポートライブラリのユーザーとして、Android Studioはコードをチェックし、これらのアノテーションに基づいて潜在的な問題にフラグを立てます。 」
James Wald、

3
BTW Android Studioは、javax.annotation.*アノテーション付きのjs305 もサポートしています
CAMOBAP 2017

19

IntelliJクラスを探している人がいる場合:Mavenリポジトリからそれらを取得できます

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 

これはIntellijに警告を表示させるものです、そうです。
Upvoteをクリック

現在のバージョン(2017年
BamaPookie

あなたの右。バージョンを更新しました。変わらないと思うけど。
Bruno Eberhard

JetBrainsアノテーションは実行時に保持されないため、たとえばGuice @Nullableサポートはそれと連携しないことに注意してください。
ピーター少佐

18

JSR305とFindBugsは同じ人によって作成されました。どちらも維持管理は不十分ですが、標準と同じように標準であり、すべての主要なIDEでサポートされています。良いニュースは、それらがそのままの状態で機能することです。

@Nonnullをデフォルトですべてのクラス、メソッド、フィールドに適用する方法を次に示します。https://stackoverflow.com/a/13319541/14731およびhttps://stackoverflow.com/a/9256595/14731を参照してください

  1. 定義する @NotNullByDefault
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;


    /**
     * This annotation can be applied to a package, class or method to indicate that the class fields,
     * method return types and parameters in that element are not null by default unless there is: <ul>
     * <li>An explicit nullness annotation <li>The method overrides a method in a superclass (in which
     * case the annotation of the corresponding parameter in the superclass applies) <li> there is a
     * default parameter annotation applied to a more tightly nested element. </ul>
     * <p/>
     * @see https://stackoverflow.com/a/9256595/14731
     */
    @Documented
    @Nonnull
    @TypeQualifierDefault(
    {
        ElementType.ANNOTATION_TYPE,
        ElementType.CONSTRUCTOR,
        ElementType.FIELD,
        ElementType.LOCAL_VARIABLE,
        ElementType.METHOD,
        ElementType.PACKAGE,
        ElementType.PARAMETER,
        ElementType.TYPE
    })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NotNullByDefault
    {
    }

2.各パッケージに注釈を追加します。 package-info.java

@NotNullByDefault
package com.example.foo;

更新:2012年12月12日の時点で、JSR 305は「休止」としてリストされています。ドキュメントによると:

実行委員会によって「休止」として投票されたJSR、またはその自然な寿命の終わりに達したJSR。

JSR 308 JDK 8に組み込んでいるように見え、JSRは@NotNullを定義していませんが、付随するものは定義していますCheckers Framework。この記事の執筆時点では、このバグのため、Mavenプラグインは使用できません:https : //github.com/typetools/checker-framework/issues/183


2
mavenのshowtopperの問題が修正されました。したがって、これは再びオプションになるはずです。
Marc von Renteln 2013

私はMavenを介してFindBugsを使用していますが、私のIDEでは何も行われません。これによりIDE固有のアノテーションが回避されます。何をお勧めしますか?
Christophe Roussy

@ChristopheRoussyあなたの質問はIDE固有です。別の質問を開いてください。
ギリ

15

静的分析とランタイム分析を区別します。内部的なものには静的分析を使用し、コードのパブリック境界にはランタイム分析を使用します。

nullであってはならないもの:

  • ランタイムチェック:「if(x == null)...」(ゼロの依存関係)または@ javax.validation.NotNull(Bean検証あり)または@ lombok.NonNull(プレーンでシンプル)またはguavas Preconditions.checkNotNull(.. 。)

    • メソッドの戻り値の型(のみ)にはOptionalを使用します。Java8またはGuavaのいずれか。
  • 静的チェック:@NonNullアノテーションを使用する

  • 適合する場合は、クラスまたはパッケージレベルで@ ... NonnullByDefaultアノテーションを使用します。これらの注釈を自分で作成します(例は簡単に見つけることができます)。
    • そうでない場合、NPEを回避するためにメソッドの戻りに@ ... CheckForNullを使用します

これにより、IDEでの警告、Findbugsによるエラー、チェッカーフレームワーク、意味のある実行時例外など、最良の結果が得られます。

静的チェックが成熟していることを期待しないでください。それらの命名は標準化されておらず、ライブラリやIDEによって処理が異なるため、無視してください。JSR305 javax.annotations。*クラスは標準のように見えますが、標準ではなく、Java9 +でパッケージが分割されます。

いくつかのメモの説明:

  • パッケージjavax.validation。*のFindbugs / spotbugs / jsr305アノテーションは、Java9 +の他のモジュールと競合し、おそらくOracleライセンスに違反します
  • Spotbugsアノテーションは、コンパイル時(https://github.com/spotbugs/spotbugs/issues/421を作成した時点)でもjsr305 / findbugsアノテーションに依存しています。
  • jetbrains @NotNullの名前は@ javax.validation.NotNullと競合します。
  • 静的チェック用のjetbrains、eclipse、checkersframeworkアノテーションは、javax.annotationsよりもJava9以降の他のモジュールと競合しないという利点があります。
  • @ javax.annotations.Nullableは、Findbugs / Spotbugsがあなた(またはあなたのIDE)が何を意味するかを意味するものではありません。Findbugsはそれを無視します(メンバーについて)。悲しいが本当(https://sourceforge.net/p/findbugs/bugs/1181
  • IDE外での静的チェックには、Spotbugs(以前のFindbugs)とcheckersframeworkの2つの無料ツールが存在します。
  • Eclipseライブラリには@NonNullByDefaultがあり、jsr305には@ParametersAreNonnullByDefaultしかありません。これらは、基本アノテーションをパッケージ(またはクラス)のすべてに適用する単なる便利なラッパーであり、簡単に独自のものを作成できます。これはパッケージで使用できます。これは、生成されたコード(lombokなど)と競合する可能性があります。
  • エクスポートされた依存関係としてロンボクを使用することは、他の人と共有するライブラリーでは避けてください。推移的な依存関係が少ないほど、より良いです
  • Bean検証フレームワークの使用は強力ですが、高いオーバーヘッドが必要になるため、手動のnullチェックを回避するだけでは過剰です。
  • フィールドとメソッドのパラメーターにOptionalを使用することは物議を醸しています(それに関する記事を簡単に見つけることができます)
  • Android nullアノテーションはAndroidサポートライブラリの一部であり、他の多くのクラスが付属しており、他のアノテーション/ツールとうまく連携しません

Java9以前は、これが私の推奨事項です。

// file: package-info.java
@javax.annotation.ParametersAreNonnullByDefault
package example;


// file: PublicApi
package example;

public interface PublicApi {

    Person createPerson(
        // NonNull by default due to package-info.java above
        String firstname,
        String lastname);
}

// file: PublicApiImpl
public class PublicApiImpl implements PublicApi {
    public Person createPerson(
            // In Impl, handle cases where library users still pass null
            @Nullable String firstname, // Users  might send null
            @Nullable String lastname // Users might send null
            ) {
        if (firstname == null) throw new IllagalArgumentException(...);
        if (lastname == null) throw new IllagalArgumentException(...);
        return doCreatePerson(fistname, lastname, nickname);
    }

    @NonNull // Spotbugs checks that method cannot return null
    private Person doCreatePerson(
             String firstname, // Spotbugs checks null cannot be passed, because package has ParametersAreNonnullByDefault
             String lastname,
             @Nullable String nickname // tell Spotbugs null is ok
             ) {
         return new Person(firstname, lastname, nickname);
    }

    @CheckForNull // Do not use @Nullable here, Spotbugs will ignore it, though IDEs respect it
    private Person getNickname(
         String firstname,
         String lastname) {
         return NICKNAMES.get(firstname + ':' + lastname);
    }
}

null可能なメソッドパラメータが逆参照されたときにSpotbugsに警告を発生させる方法はないことに注意してください(執筆時点では、Spotbugsのバージョン3.1)。たぶん、checkerframeworkはそれを行うことができます。

悲しいことに、これらの注釈は、任意の呼び出しサイトを持つライブラリのパブリックメソッドの場合と、各呼び出しサイトを認識できる非パブリックメソッドの場合を区別しません。したがって、「nullが望ましくないことを示すが、nullが渡される準備をする」という二重の意味は、単一の宣言では不可能であるため、上記の例では、インターフェイスと実装に異なるアノテーションを使用しています。

分割インターフェースアプローチが実用的でない場合、次のアプローチは妥協です。

        public Person createPerson(
                @NonNull String firstname,
                @NonNull String lastname
                ) {
            // even though parameters annotated as NonNull, library clients might call with null.
            if (firstname == null) throw new IllagalArgumentException(...);
            if (lastname == null) throw new IllagalArgumentException(...);
            return doCreatePerson(fistname, lastname, nickname);
        }

これは、クライアントがnullを渡さない(正しいコードを書く)のに役立ちますが、そうすると有用なエラーが返されます。


私は今この答えを見つけましたが、@ tkruse、どこでこれを見つけましたか:「Eclipse jdtアノテーションは静的メソッドの戻り値やその他の場合には適用されません」?(最初の部分は真実ではなく、2番目の部分はかなり曖昧です:))。
Stephan Herrmann、

@StephanHerrmann:思い出せません。箇条書きを削除しました。
tkruse

12

Eclipseにも独自のアノテーションがあります。

org.eclipse.jdt.annotation.NonNull

詳細については、http://wiki.eclipse.org/JDT_Core/Null_Analysisを参照してください。


これは、Eclipse 3.8(Juno)から統合される予定です。これにより、この点でIntelliJとEclipseが連携します。また、独自のNullアノテーション(javax.annotation.Nonnullなど)を構成できるようにする必要があり、NotNullをデフォルトにするオプションがあります。
Motti Strom

11

Java Validation API(javax.validation.constraints.*)には@Nullableアノテーションが付いていないことを指摘するだけで、静的分析のコンテキストでは非常に役立ちます。これは、Javaの非プリミティブフィールドのデフォルトであるため、実行時Bean検証に意味があります(つまり、検証/適用するものは何もありません)。述べられた目的のために、それは代替案を検討する必要があります。


7

残念ながら、JSR 308このプロジェクトのローカルのNot Null提案よりも多くの値を追加しません

Java 8単一のデフォルトアノテーションまたは独自のCheckerフレームワークは付属しません。Find-bugsまたはと同様にJSR 305、このJSRは、ほとんどが学術チームの小さな束によって十分に管理されていません。

その背後に商業的力はないのでJSR 308EDR 3(早期ドラフトレビューJCP)を今すぐ開始しますが、Java 86か月以内に出荷される予定です:-O似てい310ます。しかし308 Oracle、Javaプラットフォームへの害を最小限に抑えるために、ファウンダーから離れてそれを担当しているのとは異なります。

背後にあるもののようなすべてのプロジェクト、ベンダーとの学術クラスChecker FrameworkJSR 308独自のチェッカー注釈を作成します。

いくつかの人気の妥協が見つかり、多分に加えることができるまでは、今後数年間のためにソースコードの互換性のないを作るJava 910、またはのようなフレームワークを経由してApache CommonsGoogle Guava;-)


7

アンドロイド

この回答はAndroid固有です。Androidにはというサポートパッケージがありますsupport-annotations。これにより数十Androidの特定の注釈をしても提供して一般的なもののようにNonNullNullableなど

追加するにはサポート・注釈のパッケージを、あなたのbuild.gradleに、次の依存関係を追加します。

compile 'com.android.support:support-annotations:23.1.1'

次に使用します:

import android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}

5

これが上流(Java 8?)で整理されるのを待っている間に、独自のプロジェクトローカル@NotNull@Nullable注釈を定義することもできます。これは、デフォルトでjavax.validation.constraints は使用できない Java SEを使用している場合にも役立ちます。

import java.lang.annotation.*;

/**
 * Designates that a field, return value, argument, or variable is
 * guaranteed to be non-null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface NotNull {}

/**
 * Designates that a field, return value, argument, or variable may be null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface Nullable {}

上記は明らかにそれ自体ではこれらのアノテーションの静的分析のサポートを追加しないため、これは明らかに主に装飾または将来を保証する目的のためです。


4

Android向けに開発している場合、Eclipseにいくらか結び付いています(編集:執筆時点で、もはやではありません)。これには独自の注釈があります。Eclipse 3.8以降(Juno)に含まれていますが、デフォルトでは無効になっています。

[設定]> [Java]> [コンパイラ]> [エラー/警告]> [Null分析](下部の折りたたみセクション)で有効にできます。

「アノテーションベースのnull分析を有効にする」にチェックを入れます

http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usageには、設定に関する推奨事項があります。ただし、ワークスペースに外部プロジェクト(facebook SDKなど)がある場合、それらはそれらの推奨事項を満たしていない可能性があり、SDKの更新ごとにそれらを修正することはおそらくありません;-)

私が使う:

  1. ヌルポインターアクセス:エラー
  2. null仕様の違反:エラー(ポイント#1にリンク)
  3. 潜在的なnullポインターアクセス:警告(それ以外の場合、facebook SDKに警告があります)
  4. null注釈とnull推論の競合:警告(ポイント#3にリンク)

4
Eclipseに関連付けられていますか? 違います。
dcow 2013

1
AndroidDevingをサポートする@DavidCowden IntelliJ IDEAは、AndroidStudioが導入される少し前に利用可能だったと思います。
–MārtiņšBriedis 2013

@MārtiņšBriedisはい、それは本当です。あなたが意味したと思います@chaqke
dcow 2013年

androidとintellijには別々のアノテーションがあり、Javaに公式のアノテーションが含まれるようになるまでそのように残ることに注意してください。これらは、EclipseでEclipseの注釈を使用するための手順です。
chaqke 2013年

Eclipseに関連付けられたことはありません。任意のIDEを使用できます。
DennisK 2014年

4

大規模なプロジェクトに取り組んでいる場合は、独自の アノテーション@Nullable@NotNullアノテーションを作成した方がよい場合があります

例えば:

@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
@java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD,
                              java.lang.annotation.ElementType.METHOD,    
                              java.lang.annotation.ElementType.PARAMETER,
                              java.lang.annotation.ElementType.LOCAL_VARIABLE})
public @interface Nullable 
{
}

正しい保持ポリシーを使用すると、実行時に注釈を使用できなくなります。その観点からは、それは内部的なものにすぎません。

これは厳密な科学ではありませんが、内部クラスを使用することが最も理にかなっていると思います。

  • 内部的なものです。(機能的または技術的な影響なし)
  • 多くの多くの多くの使用法で。
  • IntelliJのようなIDEは、カスタム@Nullable/ @NotNull注釈をサポートしています。
  • ほとんどのフレームワークは、独自の内部バージョンも使用することを好みます。

追加の質問(コメントを参照):

IntelliJでこれを設定する方法は?

IntelliJステータスバーの右下隅にある「警官」をクリックします。そして、ポップアップで「検査の構成」をクリックします。次 ... 注釈を構成する


1
私はあなたのアドバイスを試しましたが、呼ばれたideaことについてvoid test(@NonNull String s) {}は何も言いませんtest(null);
user1244932

3
@ user1244932 IntelliJ IDEAですか?静的分析に使用するnull可能性アノテーションを構成できます。私は正確にはどこにいるのかわかりませんが、それらを定義する場所の1つは「ファイル」>「設定」>「ビルド、実行、配置」>「コンパイラ」であり、そこに「注釈の構成...」ボタンがあります。
Adowrath 2017年

これをまだ探している場合は、@ user1244932のスクリーンショットを参照してください。
bvdb 2017年

3

ここにはすでに回答が多すぎますが、(a)2019年であり、「標準」はまだありません Nullable、(b)Kotlinを参照する他の回答はありません。

KotlinはJavaと100%相互運用可能であり、コアNull Safety機能を備えているため、Kotlinへの参照は重要です。Javaライブラリを呼び出す場合、それらのアノテーションを利用して、KotlinツールにJava APIを受け入れるか返すかを通知できます。null

私の知る限りNullable、Kotlin org.jetbrains.annotationsと互換性のある唯一のパッケージはand android.support.annotation(nowandroidx.annotation)だけです。後者はAndroidとのみ互換性があるため、Android以外のJVM / Java / Kotlinプロジェクトでは使用できません。ただし、JetBrainsパッケージはどこでも機能します。

そのため、AndroidとKotlinでも機能する(そしてAndroid StudioとIntelliJでもサポートされる)Javaパッケージを開発する場合は、おそらくJetBrainsパッケージが最適です。

Maven:

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations-java5</artifactId>
    <version>15.0</version>
</dependency>

Gradle:

implementation 'org.jetbrains:annotations-java5:15.0'

2
うーん、そうではありません:kotlinlang.org/docs/reference/…– skagedal
21:01

3

Java 8でこれを行う別の方法があります。私は2つのことを実行して、必要なことを達成します。

  1. null許容フィールドを次のようにラップすることで、null許容フィールドを型で明示的にする java.util.Optional
  2. 構築時にnullを使用できないすべてのフィールドがnullでないことを確認する java.util.Objects.requireNonNull

例:

import static java.util.Objects.requireNonNull;

public class Role {

  private final UUID guid;
  private final String domain;
  private final String name;
  private final Optional<String> description;

  public Role(UUID guid, String domain, String name, Optional<String> description) {
    this.guid = requireNonNull(guid);
    this.domain = requireNonNull(domain);
    this.name = requireNonNull(name);
    this.description = requireNonNull(description);
  }

だから私の質問は、Java 8を使用するときに注釈を付ける必要さえあるのでしょうか?

編集:後でOptional引数で使用するのは悪い習慣だと考える人もいることを知りました、ここで賛否両論の良い議論がありますなぜJava 8のオプションを引数で使用しないのか

引数でOptionalを使用することが推奨されていないため、代替オプション。2つのコンストラクターが必要です。

  //Non null description
  public Role(UUID guid, String domain, String name, String description) {
        this.guid = requireNonNull(guid);
        this.domain = requireNonNull(domain);
        this.name = requireNonNull(name);

        // description will never be null
        requireNonNull(description);

        // but wrapped with an Optional
        this.description = Optional.of(description);
      }

  // Null description is assigned to Optional.empty
  public Role(UUID guid, String domain, String name) {
        this.guid = requireNonNull(guid);
        this.domain = requireNonNull(domain);
        this.name = requireNonNull(name);
        this.description = Optional.empty();
      }

静的分析チェッカーがどれもnullであってはならないという意図を知るために、4つの仮パラメーターすべてに@NotNullアノテーションがまだ必要だと思います。それを強制するJava言語にはまだ何もありません。防御的にプログラミングしている場合は、説明がnullでないことも確認する必要があります。
jaxzin 2016年

2
私はまだこのコードを書くことができます:new Role(null,null,null,null);。アノテーションを使用すると、私のIDEおよび静的分析で、これらのパラメーターにnullを渡すことができないことを警告します。それがなければ、コードを実行するまでわかりません。それがアノテーションの価値です。
jaxzin 2016年

2
私は、開発者が好みのIDEまたはテキストエディターを使用できる環境にもいます。相互に排他的ではありません。また、maven-pmd-pluginやSonarQubeをビルドプロセスに統合して、プルリクエストなどのマージ前のコード品質の問題を奨励し、強調表示し、さらにはゲートします。
jaxzin

2
オプションは、メソッドの引数またはプライベートフィールドとして使用するためのものではありません。例を参照してください:stuartmarks.wordpress.com/2016/09/27/vjug24-session-on-optional
assylias

1
@assyliasはい、私は後でそれが私たちに何も買わないので、それはお勧めできないと彼らが言うのを見つけました、私は彼らの理性を間違いなく理解できます。ここで私がここに置いたのは、引数description をnullにせず、クライアントコードが空の文字列を渡すことですが、多くの場合、空の文字列と値がないことを区別するのに便利です。ご意見ありがとうございます。回答を更新します。
モーツァルトブロッキーニ2016年

2

太陽は今自分のものを持っていませんか?これは何ですか:http :
//www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm

これは、過去数年間に私が使用したすべてのバージョンのJavaにパッケージされているようです。

編集:以下のコメントで述べられているように、おそらくこれらを使用したくないでしょう。その場合、私の投票はIntelliJジェットブレインアノテーションです!


10
私はそれが何であるかわからないが、パッケージ名はそれが一般的な使用を意図していないという大きな手がかりであるべきです。
スティーブンC

3
内部クラスであるため、通常、com.sun名前空間のクラスは使用しません。直接使用するためのものではありません。そして、それらの将来の可用性または動作については保証されません。com.sunアーティファクトを直接使用するには、本当に堅実なケースが必要です。
luis.espinal 2011

さらに、このような貧弱なHTML形式(Java2s.comでそれを締めくくる)で表示されたものは、いくつかの赤い旗を与えるはずです:)
luis.espinal

2

IntelliJの良い点の1つは、アノテーションを使用する必要がないことです。独自に作成することも、他の任意のツールを使用することもできます。あなたは単一のタイプにさえ制限されていません。異なる@NotNullアノテーションを使用する2つのライブラリを使用している場合は、IntelliJに両方を使用するように指示できます。これを行うには、「検査の構成」に移動し、「一定の条件と例外」検査をクリックして、「検査の構成」ボタンをクリックします。私は可能な限りNullness Checkerを使用しているので、それらのアノテーションを使用するようにIntelliJを設定しますが、他のどのツールでもそれを機能させることができます。(私はIntelliJのインスペクションを何年も使用しており、私はそれらを愛しているため、他のツールについては意見がありません。)


1

もう1つのオプションは、ANTLR 4で提供されるアノテーションです。プルリクエスト#434に続いて、@NotNullおよび@Nullableアノテーションを含むアーティファクトには、これらの属性のいずれかが誤用された場合にコンパイル時エラーや警告を生成するアノテーションプロセッサが含まれます(たとえば、両方が同じアイテムに@Nullable適用されるか、プリミティブタイプのアイテムに適用される場合)。アノテーションプロセッサは、ソフトウェア開発プロセス中に、メソッドの継承の場合を含め、これらのアノテーションのアプリケーションによって伝えられる情報が正確であることをさらに保証します。


1

Spring Frameworkを使用してアプリケーションを構築している場合は、次の依存関係にパッケージ化されたBeans Validationjavax.validation.constraints.NotNullからの使用をお勧めします。

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>

このアノテーションの主な利点は、Springがメソッドパラメータとでアノテーションされたクラスフィールドの両方をサポートすることjavax.validation.constraints.NotNullです。サポートを有効にするために必要なことは次のとおりです。

  1. Bean検証用のAPI jarおよびjsr-303 / jsr-349アノテーションのバリデーターの実装(jarにはHibernate Validator 5.xの依存関係が付属)を提供します。

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.4.1.Final</version>
    </dependency>
  2. SpringのコンテキストにMethodValidationPostProcessorを提供する

      @Configuration
      @ValidationConfig
      public class ValidationConfig implements MyService {
    
            @Bean
            public MethodValidationPostProcessor providePostProcessor() {
                  return new MethodValidationPostProcessor()
            }
      }
  3. 最後に、クラスにSpringの注釈を付けるorg.springframework.validation.annotation.Validatedと、検証はSpringによって自動的に処理されます。

例:

@Service
@Validated
public class MyServiceImpl implements MyService {

  @Override
  public Something doSomething(@NotNull String myParameter) {
        // No need to do something like assert myParameter != null  
  }
}

メソッドdoSomethingを呼び出してパラメーター値としてnullを渡そうとすると、(HibernateValidatorによって)springがをスローしConstraintViolationExceptionます。ここでは手動で作業する必要はありません。

戻り値を検証することもできます。

javax.validation.constraints.NotNullBeans Validation Framework に移行することのもう1つの重要な利点は、現時点ではまだ開発中であり、新しいバージョン2.0の新機能が計画されていることです。

どう@Nullableですか?Beans Validation 1.1にはそのようなものはありません。ええと、@NotNull注釈を付けられていないすべてのものを@NonNull効果的に "null可能" にすることを決定した場合、@Nullable注釈は役に立たないと主張できます。


1
使用しないでください。静的コード分析ではなく、ランタイム検証に使用されます。詳細については、justsomejavaguy.blogspot.com / 2011/08 /…を参照してください。出典:@ luis.espinalによる219票の削除済み回答。
koppor

@koppor:同意しません。これが使用を目的としていない場合、なぜSpringは実行時に処理するのでしょうか。また、Beans検証フレームワークでは、実行時にContextオブジェクト(現在は注釈付き/検証済みインスタンス)にアクセスできるため、純粋に実行時分析用の注釈を作成できます。
walkeros

0

Spring 5には、パッケージレベルで@NonNullApiがあります。これは、すでにSpringに依存しているプロジェクトにとっては便利な選択のようです。@NonNullおよび@Nullableにデフォルト設定されているすべてのフィールド、パラメーター、および戻り値は、異なるいくつかの場所に適用できます。

ファイルpackage-info.java:

@org.springframework.lang.NonNullApi
package com.acme;

https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.nullability.annotations

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.