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

Set*_*mon 56 java

我正在阅读番石榴的代码,在其中找到了java.util.@Nullable一些代码中的注释。我知道的含义@Nullable,但我不理解。特别是,我Nullable在package中找不到一个名为的类java.util。拜托,有人告诉我这是什么意思java.util.@Nullable

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

Tom*_*Tom 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用just进行元注释@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})
Run Code Online (Sandbox Code Playgroud)

因此,它适用于此规则。

当我们使用以下代码查看编译后的代码时,可以看出该结构不会中断执行,因为包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
}
Run Code Online (Sandbox Code Playgroud)

(这blub.Optional是一个本地类,我在其中复制了Guava代码,以获取一个最小的示例进行反编译)

如您所见,注释在那里不再存在。它只是编译器的标志,可以防止方法返回null时发出警告(并为源代码阅读器提供提示),但不会将其包含在编译后的代码中。


此编译器错误也适用于以下变量:

private @Nullable2 java.util.Optional<?> o;
Run Code Online (Sandbox Code Playgroud)

但是当注释另外获得目标类型时ElementType.FIELD,也可以接受 ,如同一JLS子句中所述:

如果TA还带有meta注释@Target(ElementType.FIELD),则该术语@TA java.lang.Object在声明和类型上下文(例如字段声明)的位置都是合法的@TA java.lang.Object f;。在这里,@ TA被认为适用于f的声明(而不适用于类型java.lang.Object),因为TA适用于字段声明上下文。


Kar*_*tik 11

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

引用checker框架手册

在标准类型名称上编写注释的正确Java语法是将注释放在简单名称部分,如java.util。@ Nullable List中所示。但是,通常最好将import java.util.List添加到源文件中,这样您就可以编写@Nullable List。

JSR308规范的第2页上也提到了它,可以在此处下载。它说:

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


ern*_*t_k 6

真正的奇怪之处是应用了以ElementType.TYPE_USE-targeted为注释的不熟悉的语法。如果查看Nullable的文档,则会看到不熟悉的目标:

...
@Target(value={TYPE_USE,TYPE_PARAMETER})
<public @interface Nullable
...
Run Code Online (Sandbox Code Playgroud)

紧随带注释类型的简单名称之前使用此注释,如以下两个示例中所示:

public static <T> @Nullable Optional<T> toJavaUtil
public static <T> java.util.@Nullable Optional<T> toJavaUtil
Run Code Online (Sandbox Code Playgroud)

我不知道这种目标的用途是什么,因此在快速阅读之后,我得到了这个简单的示例,该示例使用具有该目标的注释来选择返回类型元数据:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface InterceptedReturnValue {
    boolean value() default true;
}
Run Code Online (Sandbox Code Playgroud)

并使用:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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