java.util。@ Nullableの意味は何ですか?


56

いくつかのコードで注釈を見つけたグアバのコードを読んjava.util.@Nullableでいます。の意味は@Nullableわかりますが、わかりません。特に、Nullableパッケージで呼び出されるクラスが見つかりませんjava.util。、誰かがこれの意味は何を教えてくださいjava.util.@Nullable

public static <T> java.util.@Nullable Optional<T> toJavaUtil(
    @Nullable Optional<T> googleOptional) {
  return googleOptional == null ? null : googleOptional.toJavaUtil();
}

4
@PaulRooney私はそうは思いません。Nullable彼らが話しているにもあるように思わjavax.annotationないで、java.util
ジョセフ・サイブル復活モニカ

3
これは単なる奇妙なJava構文主義かもしれない。特に、これは基本的にはを意味するだけかもしれpublic static <T> @Nullable java.util.Optional<T> toJavaUtilませんが、そのJavaではそのように記述できませんか?
ジョセフ・サイブル復活モニカ

1
@JosephSible public static <T> @Nullable java.util.Optional<T> toJavaUtilは実際には不可能ですがOptional、インポートがすでに存在する場合のFQNを使用する理由はありません。
トム

6
@Tom Optionalスコープ内に別のものがあります。
ジョセフ・サイブル復活モニカ

2
みんなありがとう、チェッカーフレームワークでこれを見つけました。@Nullable java.util.List The correct Java syntax to write an annotation on a fully-qualified type name is to put the annotation on the simple name part, as in java.util.@Nullable List. But, it’s usually better to add import java.util.List to your source file, so that you can just write @Nullable List.
SetDaemon、

回答:


37

ラインは、public static <T> java.util.@Nullable Optional<T> toJavaUtilいつものスタイルがあるため、このように書かれているpublic static <T> @Nullable java.util.Optional<T> toJavaUtil無効です。これはJLS§9.7.4で定義されています

タイプTのアノテーションがタイプコンテキスト内のタイプ(またはタイプの一部)に適用され、Tがタイプコンテキストに適用可能であり、アノテーションが許容されない場合、これはコンパイル時エラーです。

たとえば、だけでメタ注釈が付けられた注釈タイプTAを想定し@Target(ElementType.TYPE_USE)ます。@TAが最も近い単純な名前はパッケージ名として分類されるため、用語@TA java.lang.Objectjava.@TA lang.Objectは違法です。一方、java.lang.@TA Object合法です。

の型宣言org.checkerframework.checker.nullness.qual@Nullableは次のとおりです。

@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})

したがって、このルールに適用されます。

パッケージjava.utilとクラス名Optionalが分割されているため、この構造が実行を中断しないことは、次を使用してコンパイルされたコードを見るとわかりますjavap -c [compiled class name]

class just.a.test.Main {
  just.a.test.Main();
    Code:
       0: aload_0
       1: invokespecial #1          // Method java/lang/Object."<init>":()V
       4: return

  public static <T> java.util.Optional<T> toJavaUtil(blub.Optional<T>);
    Code:
       0: aload_0
       1: ifnonnull     8
       4: aconst_null
       5: goto          12
       8: aload_0
       9: invokevirtual #2          // Method blub/Optional.toJavaUtil:()Ljava/util/Optional;
      12: areturn
}

blub.Optional逆コンパイル/コンパイルするための最小限の例を得るために、私がGuavaコードをコピーしたローカルクラスです)

ご覧のとおり、アノテーションはもう存在していません。これは、メソッドがnull(およびソースコードリーダーのヒント)を返す場合の警告を防ぐためのコンパイラのマーカーにすぎませんが、コンパイルされたコードには含まれません。


このコンパイラエラーは、次のような変数にも適用されます。

private @Nullable2 java.util.Optional<?> o;

ただしElementType.FIELD、同じJLS句に記述されているように、アノテーションがさらにターゲットタイプを取得すると、受け入れ可能になる可能性があり ます。

TAがさらにでメタアノテーションが付けられている@Target(ElementType.FIELD)場合、この用語@TA java.lang.Objectは、フィールド宣言など、宣言とタイプコンテキストの両方の場所で有効@TA java.lang.Object f;です。ここで、TAはフィールド宣言コンテキストで適用できるため、@ TAはfの宣言に適用されると見なされます(java.lang.Object型には適用されません)。


11

アノテーションを使用する場合、これは、インポートステートメントを追加する代わりに、型の完全修飾名を記述したい場合に使用される構文です。

チェッカーフレームワークマニュアルからの引用:

完全修飾型名に注釈を書き込む正しいJava構文は、java.util。@ Nullable Listのように、注釈を単純名の部分に配置することです。ただし、通常はソースファイルにインポートjava.util.Listを追加して、@ Nullable Listを作成することをお勧めします。

ここからダウンロードできるJSR308仕様の2ページにも記載されています。それは言う:

型注釈は、@ NonNull Stringまたはjava.lang。@ NonNull Stringのように、型の単純名の前に表示されます。


6

ここで奇妙なのは、ElementType.TYPE_USE-targetedアノテーションを適用するための見慣れない構文です。Nullableのドキュメントを確認すると、見慣れないターゲットが表示されます。

...
@Target(value={TYPE_USE,TYPE_PARAMETER})
<public @interface Nullable
...

このアノテーションは、次の両方のように、アノテーション付きタイプの単純名の直前に使用されます。

public static <T> @Nullable Optional<T> toJavaUtil
public static <T> java.util.@Nullable Optional<T> toJavaUtil

この種類のターゲットの用途がわからなかったので、簡単に読んだ後、この単純な例に行きました。この例では、そのターゲットを持つ注釈を使用して戻り値の型のメタデータを取得しています。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface InterceptedReturnValue {
    boolean value() default true;
}

そしてそれを使ってそれを処理しました:

public java.lang.@InterceptedReturnValue(true) String testMethod(String param) {
    return null;
}

public @InterceptedReturnValue(false) String testMethod(int param) {
    return null;
}

public static void main(String[] args) throws Exception {
    Method m = Main.class.getDeclaredMethod("testMethod", String.class);
    if(m.getAnnotatedReturnType().isAnnotationPresent(InterceptedReturnValue.class)) {
        InterceptedReturnValue config = m.getAnnotatedReturnType()
                .getAnnotation(InterceptedReturnValue.class);

        if(config.value()) {
            //logging return value enabled
        }
    }
}

チェッカーフレームワークなどの多くの有用なフレームワークが、 ElementType.TYPE_USE

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