如何在Java中避免检查null值?

4393

我使用 x != null 来避免 NullPointerException。有其他的替代方法吗?

if (x != null) {
    // ...
}

142
鼓励使用空值会使代码更难理解,也更不可靠。 - Tom Hawtin - tackline
83
不使用null比这里大多数其他建议都更好。抛出异常,不要返回或允许null。顺便说一下,“assert”关键字是无用的,因为它默认情况下是禁用的。使用一个始终启用的失败机制。 - ianpojman
4
在高级代码中应避免使用null值。发明了null引用的Tony Hoare称其为“价值数十亿美元的错误”。在此处查看一些想法:http://www.softwaregeek.net/2016/04/how-to-avoid-null-checks-in-java.html。 - Andrii Polunin
3
似乎是Java 8中的静态方法:static Objects.isNull(Object o)。可在以下链接中找到具体文档:https://docs.oracle.com/javase/8/docs/api/java/util/Objects.html - Robert R Evans
7
null最常见的误用是人们返回null而不是空集合。每次这样做都会让我发疯。停止使用null,你将生活在一个更美好的世界中。此外,通过使用"final"关键字来扩展你的代码,你将生活在一个更美好的世界中。 - Jack
显示剩余8条评论
68个回答

12

Java 8在java.util包中引入了一个新类Optional。

Java 8 Optional的优势:

1.) 不需要进行空值检查。
2.) 不会再出现运行时的NullPointerException。
3.) 我们可以开发干净整洁的API。

Optional - 一个容器对象,可以包含一个非空值或者不包含任何值。如果一个值存在,则isPresent()方法将返回true,并且get()方法将返回该值。

更多细节请参见Oracle文档: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html


需要注意的是,Optionals 主要用于返回值,作为空对象以避免连续的 NPE 问题,而不是用作在传统或遗留代码中替代空检查的方法。 - fozzybear

11
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}

2
这个方法有什么问题,我认为@tltester只是想在它为空时提供一个默认值,这是有道理的。 - Sawyer
1
在Apache commons-lang中有这样一个方法:ObjectUtils.defaultIfNull()。还有一个更通用的方法:ObjectUtils.firstNonNull(),可以用来实现降级策略:firstNonNull(bestChoice, secondBest, thirdBest, fallBack); - ivant

9
你可以使用FindBugs。他们还有一个Eclipse插件,可以帮助你找到重复的空值检查(以及其他内容),但请记住,有时你应该选择防御性编程。还有Contracts for Java可能会有所帮助。

8

我遵循以下准则来避免空指针检查。

  1. Avoid lazy initialization of member variables as much as possible. Initialize the variables in declaration itself. This will handle NullPointerExceptions.

  2. Decide on mutability of member variables early in the cycle. Use language constructs like final keyword effectively.

  3. If you know that augments for method won't be changed, declare them as final.

  4. Limit the mutation of data as much as possible. Some variables can be created in a constructor and can never be changed. Remove public setter methods unless they are really required.

    E.g. Assume that one class in your application (A.java) is maintaining a collection like HashMap. Don't provide public getter method in A.java and allow B.java to directly add an element in Map. Instead provide an API in A.java, which adds an element into collection.

    // Avoid
    a.getMap().put(key,value)
    
    //recommended
    
    public void addElement(Object key, Object value){
           // Have null checks for both key and value here : single place
           map.put(key,value);
    }
    
  5. And finally, use try{} catch{} finally{} blocks at right places effectively.


8
Java 8在java.util包中引入了一个新的类Optional。它用于表示值存在或不存在。这个新的构造的主要优点是不再需要太多的null检查和NullPointerException。它避免了任何运行时的NullPointerExceptions,并支持我们开发干净整洁的Java API或应用程序。就像Collectionsarrays一样,它也是一个容器,最多只能容纳一个值。
以下是一些有用的链接: https://www.mkyong.com/java8/java-8-optional-in-depth/ https://dzone.com/articles/java-8-optional-avoid-null-and

8
您可以通过遵循其他答案中提到的大多数方法来避免大多数NullPointerException,我只想添加一些在 Java 9 中引入的更多方式,以优雅地处理这种情况,并展示一些旧方法也可以使用,从而减少您的工作量。
  1. public static boolean isNull(Object obj)

    如果提供的引用为null,则返回true,否则返回false。

    自Java 1.8以来

  2. public static boolean nonNull(Object obj)

    如果提供的引用非空,则返回true,否则返回false。

    自Java 1.8以来

  3. public static <T> T requireNonNullElse​(T obj, T defaultObj)

    如果第一个参数不为空,则返回第一个参数,否则返回非空的第二个参数。

    自Java 9以来

  4. public static <T> T requireNonNullElseGet​(T obj, Supplier<? extends T> supplier)

    如果第一个参数不为空,则返回第一个参数,否则返回supplier.get()的非空值。

    自Java 9以来

  5. public static <T> T requireNonNull​(T obj, Supplier<String> messageSupplier)

    检查指定的对象引用不为null,否则抛出自定义的NullPointerException。

    自Java 1.8以来

有关上述函数的更多详细信息,请单击此处

你可以看到有很多答案都有很高的赞数,那么你的回答有什么特别之处呢? - Ibo
1
我只是想添加一些在Java 9中提供的更多功能。 - Mukesh A
以下是关于编程的内容,请将其翻译成中文。请仅返回翻译后的文本:然后在帖子开头使用粗体字强调它 - Ibo

7

自从Java 7开始使用java.util.Objects类,但是自从Java 8以后,你可以使用Objects.isNull(var)Objects.nonNull(var)方法来进行空指针检查。

例如:

String var1 = null;
Date var2 = null;
Long var3 = null;

if(Objects.isNull(var1) && Objects.isNull(var2) && Objects.isNull(var3))
    System.out.println("All Null");
else if (Objects.nonNull(var1) && Objects.nonNull(var2) && Objects.nonNull(var3))
    System.out.println("All Not Null");

6

另一种选择:

下面这个简单的函数可以帮助隐藏空值检查(我不知道为什么,但我没有在同一个“通用”库的一部分中找到它):

public static <T> boolean isNull(T argument) {
    return (argument == null);
}

现在您可以编写以下内容:
if (!isNull(someobject)) {
    someobject.doCalc();
}

在我看来,使用!= null的方式并不是最好的表达方式。


8
如果你不断地否定返回值,写一个函数 isNotNull 会更好吧?这是不是更清楚地表明了你的意图? - TMN
@TMN:你说得对,理想情况下我希望有一个isNull和一个isNotNull方法。 - jeha
25
我看不出这个表达比"someobject != null"更简洁。 - user1050755
编译时和运行时的开发工具,如findbugs,将更难识别重复的空值检查。此外,你最好希望Java内联isNull函数。 - IceArdor

6
我发现在这种情况下使用Guava Preconditions非常有用。我不喜欢将null值留给空指针异常,因为唯一理解NPE的方式是通过定位行号。生产版本和开发版本中的行号可能不同。
使用Guava Preconditions,我可以在一行代码中检查空参数并定义一个有意义的异常消息。
例如:
Preconditions.checkNotNull(paramVal, "Method foo received null paramVal");

6
如果您使用的是Java8或更高版本,请使用来自java.util.ObjectsisNull(yourObject)方法。 例如:
String myObject = null;

Objects.isNull(myObject); //will return true

用法:下面的代码返回非空值(如果名称不为空,则返回该值,否则返回默认值)。

final String name = "Jobin";
String nonNullValue = Optional.ofNullable(name).orElse("DefaultName");

这与 myObject == null 没有太大区别,是在Java8中引入的Predicates的lambda功能。 - PeterMmm
Objects.isNull() 自Java8开始可用(而不是Java7) - RealHowTo
@RealHowTo 感谢您指出,我已经更新了答案。实际上Objects是在Java7中引入的,isNull稍后才被添加进去。 - Jobin
1
这是一个对 Objects.isNull 的不良使用示例。这里的 filter 是多余的。如果 namenullOptional.ofNullable() 将返回 Optional.empty(),因此您可以只需执行以下操作:String nonNullValue = Optional.ofNullable(name).orElse("DefaultName"); - Araxia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接