Java 将空值传递给方法时自动引发IllegalArgumentException
我正在探索在重构部分代码库时消除null的可能性。我们已经升级到Java8,所以我们有Java 将空值传递给方法时自动引发IllegalArgumentException,java,null,java-8,optional,Java,Null,Java 8,Optional,我正在探索在重构部分代码库时消除null的可能性。我们已经升级到Java8,所以我们有可选的。为了有效地做到这一点,我们需要确保没有将null传递给我们的任何方法(这是在我们将从外部服务/库进入系统的可选中的任何潜在null值包装之后)。处理此问题的明显方法是显式检查null并在必要时抛出IllegalArgumentException,然而,这将是不合理的冗长和手动操作。是否有一种不那么手动/更简洁的方法来执行此操作?检查器框架提供了一个注释@NonNull,用于允许编译时检查是否存在可以将空
可选的。为了有效地做到这一点,我们需要确保没有将null传递给我们的任何方法(这是在我们将从外部服务/库进入系统的可选
中的任何潜在null值包装之后)。处理此问题的明显方法是显式检查null并在必要时抛出IllegalArgumentException
,然而,这将是不合理的冗长和手动操作。是否有一种不那么手动/更简洁的方法来执行此操作?检查器框架提供了一个注释@NonNull
,用于允许编译时检查是否存在可以将空值传递给注释引用的代码路径
请参阅:您可以使用对象::requirennoull
来实现此目的。例如,在构造函数中,可以执行以下操作:
this.myField = Objects.requireNonNull(myField);
如果您通过null
,它将抛出NullPointerException
避免过度使用可选。请参阅示例。您可以尝试使用具有注释的Lombok注释处理器。将参数注释为非null将在编译过程中自动生成null检查,因此您将在运行时获得NullPointerException
或IllegalArgumentException
(以您喜欢的为准)。将有其他答案建议消除检查代码的方法。这些方法似乎是通过魔法来实现的,我并不特别喜欢魔法。因此,我将向您建议一种不完全消除冗长和手动键入的方法,而是将其减少一半
使用断言。
java中的断言如下所示:
assert n != null;
如您所见,它占用一行而不是两行,并且如果您对它引发的AssertionError
异常感到满意,则不需要手动编码throw
语句。通常情况下,我们不会捕获指示bug的异常,因此在大多数情况下您应该可以,但是如果您必须确实有一个IllegalArgumentException
,那么您可以按如下方式编写断言语句:
assert n != null : new IllegalArgumentException( "n cannot be null" );
如果n
为null
将引发一个新的AssertionError
异常,该异常的“原因”将是您的IllegalArgumentException
。因此,IllegalArgumentException
将出现在堆栈跟踪中,尽管是在“引起原因:”行之后
另外一个好处是,一旦您的系统通过了所有测试,并且您知道它可以工作,您就可以避免提供-enablessertions
(-ea
)VM选项,您的程序将运行得稍微快一点,因为断言将不会被评估。我将使用以下方法,该方法结合使用注释(静态分析)和显式的、快速失败的运行时检查:
@Nonnull
注释允许兼容IDE或静态分析工具(如FindBugs)标记明显违反合同的客户端代码。作为额外的防御层,checkNotNull
保证如果由于某种原因传入了一个null
输入,checkNotNull
方法会以NullPointerException
的形式提前退出。只需使用假定为非null的参数:)if(n==null)抛出新的IllegalArgumentException(“n不能为null”)代码>也可以。但是,您可以通过VM选项禁用这些断言这一事实改变了我的观点。最后:好主意@bobbel如果你想更多地了解断言的惊人之处,我的博客上有一篇文章:断言可以在生产环境中被禁用(默认情况下是禁用的),这意味着你不应该将它们用于参数检查;实时系统接收到的输入可能超出您的控制范围。在断言后面编写这样的验证逻辑意味着程序的这一潜在关键部分可能不会在生产系统中执行。不应滥用断言进行参数检查。那是不可能讨论的。除此之外,没有必要关闭null
检查。null
检查不会带来显著的开销,而且无论如何都会被优化掉。如果调用方从未通过null
@MikeNakis,也许你没有领会我的意思。断言是好的,但只有当用于正确的目的时——用于检查程序员认为永远不会发生的条件(如中所述)。一旦一个系统“通过了所有的测试”,你只知道它在给定的测试数据下工作;您不应该断言您的测试完美地模拟了生产系统。对于参数检查,使用@Nonnull
注释(用于文档和静态分析),并辅以运行时检查null
,这是一个很好的组合。什么是可选
的“过度使用”呢?你是说在某些情况下对象可能为空,并且不应该使用可选。@w.brian,我认为链接的答案很好地解释了“过度使用”;e、 g.您不应该从方法返回Optional
,也不应该通常使用Optional
方法参数。默认情况下,它将抛出NullPointerException
。如何覆盖我自己的异常?@mwKART,我认为您不能使用自己的检查,只能使用NPE或IAE(通过lombok.nonNull.exceptionType
key配置)在哪里可以设置?你能给我一个片段吗。是否在您声明@NotNullRefer的类中:您需要在类路径中有一个文件lombok.config
。
import javax.annotation.Nonnull;
import static com.google.common.base.Preconditions.checkNotNull;
public void doSomething(@Nonnull MyClass input) {
checkNotNull(input);
/* Do something */
}