我决定编辑我的问题,看了一年之后,我改变了我使用null的方式:
@Nullable
来告诉值可以为null。毕竟,空值应该小于非空值。Optional
,因此允许以下内容:Optional.ofNullable(value).orElseGet(() -> 1);
。它没有超过Groovy的?:
和?.
运算符,但是可选提供了一些不错的工具,例如map
,filter
,等等。至于我的代码:
构造函数使用Objects.requireNonNull
检查空值,如下所示:
public Foobar(String a){ this.a = Objects.requireNonNull(a,“a”); }
Preconditions.checkNotNull
中使用时,方法都会使用来自Guava框架的Objects.requireNonNull
检查空值:
public void foobar(String a){ Preconditions.checkNotNull(a,“a”); }
使用其中一个取决于我是否重用该值。
我不是每次都检查方法参数,而是主要使用public
方法。我们的想法不是替换比我能更有效地抛出NullPointerException
的默认运行时检查。
我目前在所有参数,字段,方法结果(返回)上使用@Nonnull
或@Nullable
注释,但我想知道什么才是最好的:
@ParameterAreNonnullByDefault
对他们不起作用)。我想要一种可移植的方式(我read here我可以创建自己的注释,具有特定的名称,并且适用于findbugs)com.foobar
注释包@ParameterAreNonnullByDefault
,它是否也适用于com.foobar.example
?@Nonnull
注释时检查每个参数(我目前正在检查构造函数参数)吗?此外,自Eclipse 3.8以来,存在基于注释的空检查。但我对一些“简单”案件有疑问:
@ParameterAreNonnullByDefault
class Foobar<E extends Throwable> {
@Nullable private Constructor<E> one;
@Nullable private Constructor<E> two;
public Foobar(Constructor<E> one, @Nullable Constructor<E> two) {
this.one = Objects.requireNonNull(one, "one");
this.two = two;
}
// don't care about exceptions.
public E getInstance(String msg, Throwable t) {
if (null == two) {
return (E)one.newInstance(msg).initCause(t);
}
return two.newInstance(msg, t);
}
}
为什么告诉我两个在那个位置可以为空,为什么他警告我有可能对两个人进行无效访问?
答案 0 :(得分:1)
就two
中getInstance
变量的警告而言,空分析并不足以证明该字段不能为空。您可以使用局部变量解决此问题:
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);
}
Enable syntactic null analysis for fields
中有Preferences > Java > Compiler > Errors/Warnings > Null analysis
设置,允许使用以下代码:
if (two != null) {
return two.newInstance(msg, t);
}
没有警告。
答案 1 :(得分:1)
以下是使用Eclipse实现所有请求的方法:
自Eclipse Kepler以来,@NonNullByDefault
注释会影响所有这些位置。从Luna开始,使用Java 8并输入注释,效果为can be further fine tuned。
当您询问可移植解决方案时:在CI构建中使用Eclipse编译器并不困难,请参阅JDT FAQ,甚至可以告诉IntelliJ使用Eclipse编译器。
Java没有子包的概念。如果包名称共享一个公共前缀,则不会产生语义含义。 因此,遗憾的是,每个包装都必须单独注释。
准备好将默认值应用于所有软件包后,如果错过了软件包的默认设置,可以告诉Eclipse警告/甚至引发错误。该选项被称为:“在包装上缺少'@NonNullByDefault'注释”。
在理想的世界中,编译器将完全检查所有@NonNull
个参数,您不需要任何运行时检查。这是一个关于添加这些检查需要多少安全性的问题,但是如果你这样做,我认为没有太多理由将构造函数参数与方法参数区别对待。
也许,如果您有final @NonNull
个字段,构造函数负有特殊责任并需要更多检查,但这基本上取决于您的代码风格和安全要求。
Eclipse仅对局部变量执行全流分析。它是以这种方式精心设计的,以保护您免受risks of side-effects, aliasing and concurrency的影响,尽管事先进行了空检查,但每个都可能导致NPE。对于字段的所谓“语法分析”已被引入作为(有限的)折衷,但真正的解决方案必须是,将值提取到局部变量中,在那里可以对其进行全面分析。 Eclipse甚至可以快速修复此更改。
答案 2 :(得分:0)
我会使用外部工具Checker Framework Nullness Checker来回答您的问题。它有一个Eclipse plug-in,它读取Eclipse和FindBugs使用的注释。它的分析优于内置的Eclipse nullness分析,但它的IDE集成并不像Eclipse那样好。两者都是值得的工具,你可以决定哪一个最适合你。
默认情况下,如何判断我的字段和方法结果是否为空?
那是the default。你不必做任何事情。
如果我使用@ParameterAreNonnullByDefault注释com.foobar包,它是否也适用于com.foobar.example?
您根本不必更改默认设置(尽管您可以在某些或所有代码位置使用@Nullable
作为默认设置)。
@Nonnull注释时,我应该检查每个参数(我目前正在检查构造函数参数)吗?
如果您担心归零度分析不合理,您只需要编写运行时检查 - 也就是说,即使您的代码可以抛出空指针异常,或者如果您没有运行分析,分析也不会出现错误在你的整个计划。 Eclipse和FindBugs的零点分析都不合理。 Checker框架设计合理。当然,任何工具都可能包含错误。
此外,自Eclipse 3.8以来,存在基于注释的空检查。但我对一些&#34;简单&#34;有问题。情况下:
Checker Framework精确处理这个简单的案例 - 完全按照您的意愿处理。
更具体地说,Checker Framework在检查单线程代码时会这样做。
如果您的代码是多线程的,那么您可以提供-AconcurrentSemantics
命令行选项。在这种情况下,Checker Framework将发出警告,因为另一个线程可能会在检查和使用之间重置two
。如果您的代码是多线程的并且其他线程同时修改字段,那么您可能想要使用锁。如另一个答案所示,将值复制到局部变量是一个坏主意。它不仅会降低代码的可读性,而且并不一定能按照您的意愿行事;例如,另一个线程可能违反表示不变量并导致代码以其他方式崩溃。