java.util。@ Nullable是什么意思?

时间:2019-10-09 03:16:14

标签: java

我正在阅读the code of Guava,在其中找到了一些代码中的注释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();
}

3 个答案:

答案 0 :(得分: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 java.lang.Objectjava.@TA lang.Object是非法的,因为@TA最接近的简单名称被分类为程序包名称。另一方面,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被认为适用于f的声明(而不适用于类型java.lang.Object),因为TA适用于字段声明上下文。

答案 1 :(得分:11)

使用注释时,这是您要为类型编写完全限定名称而不是添加import语句时使用的语法。

引用checker framework manual

  

在完全限定的条件下编写注释的正确Java语法   类型名称是将注释放在简单名称部分,例如   java.util。@ Nullable列表。但是,通常最好添加导入   java.util.List到您的源文件,以便您可以编写   @空列表。

JSR308 规范的第2页也提到了该问题,可以下载here。它说:

  

类型注释出现在类型的简单名称之前,例如   @NonNull字符串或java.lang。@ NonNull字符串。

答案 2 :(得分:6)

这里确实有一个奇怪的地方,就是应用以ElementType.TYPE_USE为目标的注释不熟悉的语法。 如果您查看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
        }
    }
}

我敢肯定,许多有用的框架(例如checkerframework)会最适当地使用ElementType.TYPE_USE