4

Java 8 类型注释 (JSR 308) 允许类型检查器执行静态代码分析。例如,检查器框架可以通过注释检查可能的空值。@NonNull

各种项目定义了自己的NonNull注解,例如:

  • org.checkerframework.checker.nullness.qual.NonNull
  • edu.umd.cs.findbugs.annotations.NonNull
  • javax.annotation.Nonnull
  • javax.validation.constraints.NotNull
  • lombok.NonNull
  • org.eclipse.jdt.annotation.NonNull
  • 等(参见Checker 框架手册,第 3.7 节

对于此类注释,我希望@interface具有@Retention(RetentionPolicy.CLASS),因为在运行时通常不需要它们。最重要的是,代码对各自的库没有任何运行时依赖项。

虽然org.eclipse.jdt.annotation.NonNull遵循这种方法,但大多数其他NonNull注释,如javax.annotation.Nonnull(JSR 305) 及其org.checkerframework.checker.nullness.qual.NonNull本身,都具有@Retention(RetentionPolicy.RUNTIME). RetentionPolicy.RUNTIME这些注释中有什么特别的原因吗?


澄清:Checker 框架支持注释中的注释以实现向后兼容性。然而,在 Java 8 中使用它们只是为了避免运行时依赖似乎是一种肮脏的 hack。

4

2 回答 2

6

这是一个很好的问题。

为了在编译时进行静态检查,CLASS保留就足够了。请注意,SOURCE保留是不够的,因为单独编译:当对一个类进行类型检查时,编译器需要读取它使用的库上的注释,并且单独编译的库只能作为类文件提供给编译器。

注释设计者使用RUNTIME保留来允许工具执行运行时操作。这可能包括检查注释(如断言语句)、动态加载代码的类型检查、检查强制转换和instanceof操作、更精确地解析反射等等。今天这样的工具并不多,但注释设计者希望在未来适应它们。

您用 评论说@Retention(RetentionPolicy.CLASS),“代码对相应的库没有任何运行时依赖项。” 这实际上@Retention(RetentionPolicy.RUNTIME)也是如此!请参阅此堆栈溢出问题: 为什么缺少注释在运行时不会导致 ClassNotFoundException?.

总而言之,使用CLASS保留在运行时花费的空间量可以忽略不计,可以在未来实现更多潜在用途,并且不会引入运行时依赖性。

对于 Checker Framework,它提供运行时测试,例如isRegex(String). 如果您的代码使用此类方法,您的代码将依赖于 Checker Framework 运行时库(它比整个 Checker Framework 本身小,并且具有更宽松的许可证)。

于 2016-08-16T15:09:16.167 回答
1

每个注释都有它的目的!

javax.validation.constraints.NotNull

这个是由bean验证规范定义的,用于在运行时执行非空检查,所以需要在运行时保留它来执行,例如,表单验证...

@RetentionPolicy.SOURCE => 通常用于文档 @RetentionPocily.CLASS => 允许将一些信息提供给编译器而不是 JVM(例如,在编译期间执行代码生成) @RetentionPolicy.RUNTIME => 允许检索注解信息在 JVM 级别(所以在运行时)。

问候,

洛伊克

于 2016-08-16T12:52:38.343 回答