Java JSR-308:关于非null、parameterRenonNullByDefault和Eclipse开普勒检测它的方式的澄清

Java JSR-308:关于非null、parameterRenonNullByDefault和Eclipse开普勒检测它的方式的澄清,java,eclipse,Java,Eclipse,我决定编辑我的问题,在一年之后,我改变了使用空值的方式: 我不使用Eclipse内置的空检查,因为我发现它相当原始(可能有点难以理解) 我使用@Nullable告诉您一个值可以为null。毕竟,空值应该少于非空值 我使用的是Java8,我倾向于使用Optional,因此允许以下内容:Optional.ofNullable(value).orElseGet(()->1)。它并没有打败Groovy的?:和?。操作符,但可以选择提供一些不错的工具,如映射,过滤器,等等 至于我的代码: 构造函数使

我决定编辑我的问题,在一年之后,我改变了使用空值的方式:

  • 我不使用Eclipse内置的空检查,因为我发现它相当原始(可能有点难以理解)
  • 我使用
    @Nullable
    告诉您一个值可以为null。毕竟,空值应该少于非空值
  • 我使用的是Java8,我倾向于使用
    Optional
    ,因此允许以下内容:
    Optional.ofNullable(value).orElseGet(()->1)。它并没有打败Groovy的
    ?:
    ?。
    操作符,但可以选择提供一些不错的工具,如
    映射
    过滤器
    ,等等
至于我的代码:

  • 构造函数使用
    对象检查空值。requirennull
    ,如下所示:

    公共Foobar(字符串a){ this.a=Objects.requirennull(a,“a”); }

  • 方法使用
    先决条件检查空值。每当我在项目或
    对象中使用Guava framework时,都会检查它。requirennull

    公共void foobar(字符串a){ 先决条件。checkNotNull(a,“a”); }

使用一个或另一个取决于我是否重用该值

我不是每次都检查方法参数,而是主要检查
public
方法。这样做的目的不是取代默认的运行时检查,因为它比我能做的更有效地抛出
NullPointerException


我目前正在对所有参数、字段、方法结果(返回)使用
@Nonnull
@Nullable
注释,但我想知道什么才是真正最好的:

  • 我如何判断我的字段和方法结果默认为非空?(默认情况下,
    @parameterRenonNull
    不适用于它们)。我想要一种可移植的方式(我希望我可以用特定的名称创建自己的注释,这将适用于findbugs)
  • 如果我用
    @ParameterAreNonnullByDefault
    注释package
    com.foobar
    ,它是否也适用于
    com.foobar.example
  • 当由
    @Nonnull
    注释时,我是否应该检查每个参数(我当前正在检查构造函数参数)
此外,自Eclipse3.8以来,还存在基于注释的空检查。但我有一些“简单”的问题:

@ParameterRenonNullByDefault
福巴级{
@可为空的私有构造函数1;
@可为空的私有构造函数2;
公共Foobar(构造函数一,@Nullable构造函数二){
this.one=Objects.requirennoull(一,“一”);
这个2=2;
}
//不要在意例外情况。
公共E getInstance(字符串msg,Throwable t){
if(null==2){
返回(E)一个.newInstance(msg).initCause(t);
} 
返回2.newInstance(msg,t);
}
}

为什么要告诉我在那个位置two可以为null,为什么他要警告我对two的潜在null访问?

getInstance
two
变量的警告而言,null分析不够聪明,无法得出字段不能为null的结论。您可以通过使用局部变量来解决此问题:

public E getInstance(String msg, Throwable t) { 
  final Constructor<E> localTwo = two;
  if (null == localTwo) {
    return (E)one.newInstance(msg).initCause(t);
  }
  return localTwo.newInstance(msg, t);
}

没有警告。

以下是使用Eclipse实现所有请求的方法:

字段和方法返回的默认值为非null 自Eclipse开普勒以来,注释会影响所有这些位置。从Luna开始,使用Java8和类型注释,效果非常好

当您询问可移植解决方案时:在CI构建中也使用Eclipse编译器并不困难,请参阅,甚至可以告诉IntelliJ使用Eclipse编译器

每个包的默认值 Java没有子包的概念。如果包名称共享一个公共前缀,则没有语义含义。 因此,遗憾的是,每个包都必须单独注释

一旦您准备好将默认值应用于所有包,如果您错过了包的默认值,Eclipse会被告知警告您/甚至引发错误。该选项称为:“包上缺少'@NonNullByDefault'注释”

运行时检查 在理想情况下,编译器将完全检查所有
@NonNull
参数,您不需要任何运行时检查。添加这些检查需要多大的安全性,这是一个问题,但如果您这样做,我看不出有什么理由将构造函数参数与方法参数区别对待

也许,如果您有
final@NonNull
字段,那么构造函数有特殊的责任,应该进行更多的检查,但这基本上是您的代码样式和安全要求的问题

Eclipse中的意外警告
Eclipse仅对局部变量执行全流分析。它是以这种方式精心设计的,以保护您免受攻击,尽管之前进行了空检查,但每种攻击都可能导致NPE。所谓的字段“语法分析”是作为一种(有限的)折衷方案引入的,但真正的解决方案必须是,将值提取到局部变量中,以便对其进行全面分析。Eclipse甚至为这一变化提供了一个快速解决方案。

我将使用一个外部工具“的”来回答您的问题。它有一个函数,读取Eclipse和FindBugs使用的注释。它的分析比内置的Eclipse空性分析更好,但是它的IDE集成不如Eclipse的好。两者都是值得的工具,你可以决定哪一个最适合你

我如何判断我的字段和方法结果默认为非空

就是。你什么都不用做

如果我默认使用@ParameterRenonNullByDefault注释包com.foobar,它是否也适用于com.foobar.example

您根本不需要更改默认值(尽管您可以,如果出于某种原因,您想在部分或全部代码中使用
@Nullable
作为默认值)
public E getInstance(String msg, Throwable t) { 
  final Constructor<E> localTwo = two;
  if (null == localTwo) {
    return (E)one.newInstance(msg).initCause(t);
  }
  return localTwo.newInstance(msg, t);
}
if (two != null) {
  return two.newInstance(msg, t);
}