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

Naw*_*waz 20 java annotations java-7 java-8 try-with-resources

只是想知道哪些注释可以用于在try-with-resources语句中声明的变量,这是根据其语法允许的.语言规范(Java 7)的第14.20.3节内容如下:

TryWithResourcesStatement:
    tryResourceSpecification Block Catches opt最后选择

ResourceSpecification:
    (资源;选择 )

资源:
    资源;资源

资源:
    VariableModifiers opt类型VariableDeclaratorId =表达式

VariableModifiers扩展为(第14.4节),

VariableModifiers:
    VariableModifier
    VariableModifiers VariableModifier

VariableModifier:
    Annotation之一 final

你去:VariableModifier可以有注释.嗯,这基本上意味着,我们可以这样写:

try( @SomeAnnotation SomeType obj = createSomeType() ) { 
  //some code
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:如何以及什么样的注释可以用于资源尝试并实现什么样的行为?任何创新的想法?有人用过它们吗?

Hug*_* M. 15

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

我认为没有什么特别的东西可以绑定资源和注释尝试,它不是语法中的特殊情况; 在这方面,这些变量(在try-with-resources语句中声明)与其他局部变量相同,语法也允许注释:

  • Java 7引入了try-with-resources语句,您可以在其中声明一个将获得特殊处理的变量.
  • 早在Java 5中,当引入注释时,语法一直允许对局部变量声明进行注释(但是我们必须等待Java 6才能获得用于注释处理的可用API)
  • 不过,即使Java 7中是不可能的注释处理器访问本地变量的注释.关于局部变量的唯一注释是"可用的",@SuppressWarnings但是编译器本身特别处理了这个注释,没有办法让你勾选它.
  • 除了"声明上下文"之外, Java 8引入了一种新的注释上下文,现在有了"类型上下文",现在注释Target可以是ElementType.TYPE_USE

所以答案(使用Java 8)与局部变量的任何注释相同.


(关于Java 8的新"类型注释"的一些琐事)

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

注释可能出现的语法位置被拆分为声明上下文,其中注释适用于声明,类型上下文,其中注释适用于声明和表达式中使用的类型.

这样的注释不会在运行时保留,但可以在编译时用于各种"检查".请参阅checker框架,它构建于JSR-308的工作之上(如果我理解正确的话,由同一作者完成).

非常快,因为它很有趣,现在我们可以这样做:

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

这种"类型注释"的例子:

Checker Framework提供了一些可以使库和应用程序开发人员受益的类型注释,例如:
@NonNull- 编译器可以确定代码路径可能接收空值的情况,而无需调试NullPointerException.
@ReadOnly - 编译器将标记任何更改对象的尝试.这类似于Collections.unmodifiableList,但更通用并在编译时验证.
@Regex - 提供编译时验证,即用作正则表达式的String是格式正确的正则表达式.
@Tainted@Untainted-在系统命令,或在日志流的敏感信息被使用,不应该一起使用的数据的标识类型,例如远程用户输入.
@m - 测量单位确保正确使用和比较用于测量对象的数字,或者已经过正确的单位转换.

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


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

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

所以,我可以想到一个"特殊"用途,但我甚至不确定它是否会非常有用,因为可能有其他方法可以实现这一点:对于在try-with-resources中声明的某些特定类型的资源声明,您可能需要确保资源在关闭之前完全消耗(我已经看到类似于HTTP客户端库的内容以及读取标题的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. */
}
Run Code Online (Sandbox Code Playgroud)

这个注释会有目标ElementType.LOCAL_VARIABLE(因此不需要新的Java 8注释类型,但需要java 8可以处理),并且检查器应该验证变量是否在try-with-resources语句中有效声明(编译器无法阻止从在任何本地变量上使用它,然后分析源树以确定是否按需要使用资源.
以100%正确的方式实现这样的检查器可能是不可能的,但在纸面上看起来可能会检查一些已知的坏模式,并且当目标变量在try-with中声明时,它将是有意义的.资源声明.

另一个想法(仍然是变量而不是类型使用),也是非常低的有用性:@MustNotEscape如果你想控制变量没有被传递给另一个方法,因为(出于与上面类似的原因)你想要能够控制发生的一切对于后面的对象(例如,如在先前的想法中),并且如果变量被传递则将更难以实现.

为了说明这样的事情是模糊的,这里有一个框架的例子,它希望你在某个块内跟随它们的"嵌入式DSL",如果你不这样做就会失败.可以想象一个注释,以帮助检查对资源尝试块内的资源的假设框架施加的类似约束的遵从性.
不是说这将是一个很好的设计...(我在ModelMapper的情况下,DSL只是他们在java 8之前提出的一个聪明的技巧,他们现在有更好和更安全的lambdas解决方案)


Ser*_*kov 7

您可以应用于局部变量的唯一类型的注释(包括trytry-with-resources块中的变量赋值)就是具有该注释的注释@Target({ElementType.LOCAL_VARIABLE}).那些在运行时(通过反射)无法访问,因此它们只能由编译器访问.

它们可能有用的例子:

  • @SuppressWarnings("unchecked") - 如果您在a中有未选中的作业 try(...)
  • 使用JSR 305(软件缺陷检测注释)注释,例如@Nullable,@Nonnull