我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
当前回答
通过遵循问题的大多数其他答案,您可以避免很多事情,以避免NullPointerException。我只想添加Java9中引入的其他一些方法,以优雅地处理这种情况,并展示一些旧的方法也可以使用,从而减少您的工作量。
公共静态布尔值isNull(对象obj)如果提供的引用为null,则返回true,否则返回错误。自Java 1.8以来公共静态布尔值nonNull(对象obj)如果提供的引用为非null,则返回true,否则返回错误。自Java 1.8以来公共静态<T>T requireOnNullElse(T对象,T默认对象)如果第一个参数为非null,则返回第一个参数,否则返回非空的第二个参数。自Java 9以来公共静态<T>T requireOnNullElseGet(T obj,供应商<?扩展T>供应商)如果第一个参数为非空,则返回第一个参数,否则返回supplier.get()的非空值。自Java 9以来公共静态<T>T requireOnNull(T obj,供应商<字符串>消息供应商)检查指定的对象引用是否为空,否则将引发自定义的NullPointerException。自Java 1.8以来
有关上述功能的更多详细信息,请参阅此处。
其他回答
Java8在Java.util包中引入了一个新的类Optional。它用于表示值是否存在。这种新构造的主要优点是不再有太多的空检查和NullPointerException。它避免了任何运行时NullPointerExceptions,并支持我们开发干净整洁的Java API或应用程序。与集合和数组一样,它也是一个最多只能容纳一个值的容器。
下面是一些有用的链接,您可以关注
https://www.mkyong.com/java8/java-8-optional-in-depth/
https://dzone.com/articles/java-8-optional-avoid-null-and
我喜欢Nat Pryce的文章。以下是链接:
用多态调度避免空值避免使用“告诉,不要问”风格的null
在文章中,还有一个指向Java Maybe Type的Git存储库的链接,我觉得这很有趣,但我不认为单独使用它会降低检查代码膨胀。在互联网上做了一些研究之后,我想主要通过仔细设计可以减少空码膨胀。
在我看来,这似乎是初级到中级开发人员在某个时候往往会面临的一个相当普遍的问题:他们要么不知道,要么不信任他们正在参与的合同,并防御性地过度检查空值。此外,在编写自己的代码时,他们倾向于依赖于返回null来指示某些内容,从而要求调用者检查null。
换言之,有两种情况会出现空检查:
在合同条款中,null为有效响应;和如果它不是有效的响应。
(2) 很容易。从Java1.7开始,您可以使用Objects.requireOnNull(foo)
该方法的“正确”用法如下。该方法返回传递给它的对象,如果对象为空,则抛出NullPointerException。这意味着返回的值总是非空的。该方法主要用于验证参数。
public Foo(Bar bar) {
this.bar = Objects.requireNonNull(bar);
}
它也可以像断言一样使用,因为如果对象为空,它会抛出异常。在这两种情况下,都可以添加一条消息,该消息将显示在异常中。下面将其用作断言并提供消息。
Objects.requireNonNull(someobject, "if someobject is null then something is wrong");
someobject.doCalc();
当值为null但不应为null时,通常会引发特定异常(如NullPointerException),这有利于引发更一般的异常(如AssertionError)。这是Java库采用的方法;当参数不允许为null时,支持NullPointerException而不是IllegalArgumentException。
(1) 有点难。如果你无法控制正在调用的代码,那么你就被卡住了。如果null是有效的响应,则必须检查它。
然而,如果是由你控制的代码(通常是这样),那就另当别论了。避免使用null作为响应。对于返回集合的方法,很容易:总是返回空集合(或数组)而不是空值。
对于非集合,这可能会更困难。举个例子:如果您有这些接口:
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}
其中Parser接收原始用户输入并找到要做的事情,如果您正在实现某个命令行接口。现在,如果没有适当的操作,您可能会使契约返回null。这导致了你所说的空值检查。
另一种解决方案是从不返回null,而是使用空对象模式:
public class MyParser implements Parser {
private static Action DO_NOTHING = new Action() {
public void doSomething() { /* do nothing */ }
};
public Action findAction(String userInput) {
// ...
if ( /* we can't find any actions */ ) {
return DO_NOTHING;
}
}
}
比较:
Parser parser = ParserFactory.getParser();
if (parser == null) {
// now what?
// this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
// do nothing
} else {
action.doSomething();
}
to
ParserFactory.getParser().findAction(someInput).doSomething();
这是一个更好的设计,因为它导致了更简洁的代码。
也就是说,findAction()方法抛出带有有意义的错误消息的异常可能是完全合适的——尤其是在这种情况下,您依赖于用户输入。findAction方法抛出一个异常比调用方法用简单的NullPointerException(没有解释)爆炸要好得多。
try {
ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
userConsole.err(anfe.getMessage());
}
或者,如果您认为try/catch机制太难看,而不是Do Nothing,那么您的默认操作应该向用户提供反馈。
public Action findAction(final String userInput) {
/* Code to return requested Action if found */
return new Action() {
public void doSomething() {
userConsole.err("Action not found: " + userInput);
}
}
}
如果您使用(或计划使用)JetBrains IntelliJ IDEA、Eclipse或Netbeans等Java IDE或findbugs等工具,那么您可以使用注释来解决这个问题。
基本上,你有@Nullable和@NotNull。
您可以在方法和参数中使用,如下所示:
@NotNull public static String helloWorld() {
return "Hello World";
}
or
@Nullable public static String helloWorld() {
return "Hello World";
}
第二个示例无法编译(在IntelliJ IDEA中)。
在另一段代码中使用第一个helloWorld()函数时:
public static void main(String[] args)
{
String result = helloWorld();
if(result != null) {
System.out.println(result);
}
}
现在IntelliJ IDEA编译器将告诉您,检查是无用的,因为helloWorld()函数永远不会返回null。
使用参数
void someMethod(@NotNull someParameter) { }
如果你写的东西像:
someMethod(null);
这无法编译。
最后一个使用@Nullable的示例
@Nullable iWantToDestroyEverything() { return null; }
这样做
iWantToDestroyEverything().something();
你可以肯定这不会发生。:)
这是一个很好的方法,可以让编译器检查比通常更多的东西,并强制执行您的契约以使其更强大。不幸的是,并非所有编译器都支持它。
在IntelliJ IDEA 10.5及更高版本中,他们添加了对任何其他@Nullable@NotNull实现的支持。
查看博客文章更灵活和可配置的@Nullable/@NotNull注释。
如果您认为对象不应为空(或是错误),请使用断言。如果您的方法不接受null参数,请在javadoc中说它并使用断言。
您必须检查对象!=仅当您想处理对象可能为空的情况时才为空。。。
有人建议在Java7中添加新注释,以帮助处理null/notnull参数:http://tech.puredanger.com/java7/#jsr308