java - 在try-with-resources中声明的变量的注释?

标签 java java-8 annotations java-7 try-with-resources

只是想知道在try-with-resources语句中声明的变量可以使用什么批注,按其语法是允许的。语言规范(Java 7)中的14.20.3部分内容如下:

TryWithResourcesStatement:
    try ResourceSpecification Block Catchesopt Finallyopt

ResourceSpecification:
    ( Resources ;opt )

Resources:
    Resource Resource ; Resources

Resource:
    VariableModifiersopt Type VariableDeclaratorId = Expression



并且VariableModifiers扩展为(第14.4节),

VariableModifiers:
    VariableModifier
    VariableModifiers VariableModifier

VariableModifier: one of
    Annotation final



到此为止:VariableModifier可以具有注释。好吧,这基本上意味着,我们可以这样写:
try( @SomeAnnotation SomeType obj = createSomeType() ) { 
  //some code
}

所以我的问题是:尝试资源中可以怎样使用哪种注释以及实现哪种行为?有什么创新想法吗?有人用过吗?

最佳答案

不是在Java 7中,而是我怀疑您标记了java-7只是因为这是引入try-with-resources的版本,并且您仍然对Java 7以外的可能用途感兴趣(我认为这个问题对于Java> = 8非常有趣) 。

我认为绑定(bind)try-with-resources和批注没有什么特别的,在语法上不是特殊的情况。在这方面,这些变量(在try-with-resources语句中声明)与其他局部变量相同,并且语法也允许注释:

  • Java 7引入了try-with-resources语句,您可以在其中声明将获得special treatment的变量。
  • 早在Java 5引入注释时,语法就一直允许在局部变量声明中进行注释(但我们必须等待Java 6来获得用于注释处理的可用API)
  • 但是,即使使用Java 7,注释处理器也可以使用not possible来访问局部变量的注释。本地变量上唯一可用的注释是@SuppressWarnings,但编译器本身已对其进行了特殊处理,因此您无法将其挂钩。
  • Java 8除了“声明上下文”之外还引入了一种新的注释上下文,现在有“类型上下文”,现在注释Target可以是ElementType.TYPE_USE

  • 因此,答案(对于Java 8)为,与对本地变量的任何注释相同。

    (有关Java 8的新“类型注释”的一些琐事)

    ...,这就是变得有趣的地方:使用注释任何类型!

    The syntactic locations where annotations may appear are split into declaration contexts , where annotations apply to declarations, and type contexts, where annotations apply to types used in declarations and expressions.



    此类注释不会在运行时保留,但可以在编译时用于各种“检查”。请参阅checker framework,它建立在为JSR-308完成的工作之上(如果我理解正确,则由same author完成)。

    很快,因为它很有趣,现在我们可以这样做:
    @NonNull Object @Nullable [] array; // Nullable array of non-null objects
    @Nullable Object @NonNull [] array; // Non-null array of nullable objects
    
    @Foo List<@Foo Integer> doSomething(@Foo Integer @Foo [] arrayOfIntegers, @Foo long x) {
        arrayOfIntegers[0] = (@Foo int) x;
        return Arrays.asList(arrayOfIntegers);
    }
    

    这样的"type annotations"的示例:

    The Checker Framework provides a few Type Annotations that could benefit both library and application developers, such as:
    @NonNull – The compiler can determine cases where a code path might receive a null value, without ever having to debug a NullPointerException.
    @ReadOnly – The compiler will flag any attempt to change the object. This is similar to Collections.unmodifiableList, but more general and verified at compile time.
    @Regex – Provides compile-time verification that a String intended to be used as a regular expression is a properly formatted regular expression.
    @Tainted and @Untainted – Identity types of data that should not be used together, such as remote user input being used in system commands, or sensitive information in log streams.
    @m – Units of measure ensures that numbers used for measuring objects are used and compared correctly, or have undergone the proper unit conversion.



    但是,如果在try-with-resources语句的上下文中特别有用,则没有一个(我的意思是,没有比任何其他地方更多或更少)。

    回到问题:是否有用于局部变量的注释的方法,这些注释在try-with-resources语句中声明时会特别有趣?

    我认为在这种情况下,应用程序本质上将被限制为编译时检查,因为这样的注释将在局部变量或类型使用上,并且在运行时都不可用(或实际上不可用):

    二进制变量中未保留本地变量的
  • according to the JLS批注
    类型使用的
  • 批注是written to the class file,但still not available at runtime by reflection(您需要自己解析类文件!)

  • 因此,我可以想到一种“特殊”用途,但是我什至不确定这是否会非常有用,因为可能还有其他方法可以实现此目的:对于在try-with-resources中声明的某些特定类型的资源语句,您可能需要确保在关闭资源之前已完全消耗该资源(我已经通过HTTP客户端库以及读取 header 的API部分看到了类似的东西-忘记了细节)。
    /* Say getResponse() taps into a third-party library that has a quirk:
     * a response object must be consumed entirely before being closed. */
    try(@MustConsumeEntirely Stream<String> lines = getResponse()) {
        lines.findFirst().ifPresent(System.out::println);
        /* The stream is not entirely consumed (unless it is only 1 line but there is no way to tell).
         * A smart checker could catch this and issue a warning. */
    }
    

    此注释将具有目标ElementType.LOCAL_VARIABLE(因此不需要新的Java 8注释类型,但将要求Java 8可处理),并且检查器可能应验证该变量是否在try-with-resources语句中有效地声明了(编译器不能阻止在任何局部变量上使用它),然后分析源树以确定是否按需使用了资源。
    可能不可能以100%正确的方式实现这种检查器,但是在纸上看起来可以检查一些已知的错误模式,并且当在try-with-中声明目标变量时,这在大多数情况下是有意义的资源声明。

    另一个想法(仍然使用变量而不是类型使用),其实用性也很低:@MustNotEscape,如果您想控制不将变量传递给另一个方法,因为(出于与上述类似的原因)您希望能够控制所有发生在后面的对象上(例如,按照先前的想法),如果传递变量,则将很难完成。

    为了说明这种事情几乎是可能的,框架的here is an example期望您在某个块内遵循其“嵌入式DSL”,否则请访问fails。可以想象一下一种注释,以帮助检查是否有一个假设框架对“尝试使用资源”块中的资源施加的类似约束的合规性。
    不过,并不是说这将是一个好的设计……(就ModelMapper而言,DSL只是他们在Java 8之前提出的一个巧妙技巧,现在他们有了使用lambda的更好,更安全的解决方案)

    关于java - 在try-with-resources中声明的变量的注释?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45464920/

    相关文章:

    java - 使用双冒号 (::) 调用 ExecutorService 中的方法

    java.security.InvalidKeyException : Wrong key size during decryption

    java - 如何动态填充注释

    php - 基于注释的 symfony2 表单创建器

    java - 空请求正文未被 Spring @RequestBody @Valid 注释捕获

    java - 如何在 jshell 中使用/设置截断命令中的选择器?

    java - HTTP 状态 500 - 在第 39 行处理 JSP 页面/Query.jsp 时发生异常

    java - 以父类(super class)为参数并操作子类的方法

    java - 如果我用最新的 JDK 编译了一个 Java 文件,旧的 JVM 是否能够运行 .class 文件?

    java - 此计算机上存在更新版本的 Java 8