88

在调用对象的函数之前,我需要检查对象是否为 null,以避免抛出NullPointerException.

解决此问题的最佳方法是什么?我考虑过这些方法。
哪一个是 Java 的最佳编程实践?

// Method 1
if (foo != null) {
    if (foo.bar()) {
        etc...
    }
}

// Method 2
if (foo != null ? foo.bar() : false) {
    etc...
}

// Method 3
try {
    if (foo.bar()) {
        etc...
    }
} catch (NullPointerException e) {
}

// Method 4 -- Would this work, or would it still call foo.bar()?
if (foo != null && foo.bar()) {
    etc...
}
4

18 回答 18

122

方法4最好。

if(foo != null && foo.bar()) {
   someStuff();
}

将使用短路评估,这意味着如果 a 的第一个条件logical AND为假,则结束。

于 2013-06-25T16:11:38.030 回答
16

最后一个也是最好的。即 逻辑与

  if (foo != null && foo.bar()) {
    etc...
}

因为在逻辑上&&

不需要知道右手边是什么,结果一定是假的

喜欢阅读:Java 逻辑运算符短路

于 2013-06-25T16:10:19.250 回答
5
  • 不要抓NullPointerException。这是一个不好的做法。最好确保该值不为空。
  • 方法#4 适合你。它不会评估第二个条件,因为 Java 有短路(即,如果后续条件不改变布尔表达式的最终结果,则不会评估后续条件)。在这种情况下,如果逻辑 AND 的第一个表达式计算结果为 false,则不需要计算后续表达式。
于 2013-06-25T16:12:37.097 回答
5

方法 4 无疑是最好的,因为它清楚地表明会发生什么并使用最少的代码。

方法 3 在各个层面上都是错误的。您知道该项目可能为空,因此这不是特殊情况,您应该检查它。

方法 2 只是让它变得比它需要的更复杂。

方法 1 只是方法 4,多了一行代码。

于 2013-06-25T16:13:43.577 回答
4

Java 7中,您可以使用Objects.requireNonNull(). 添加一个Objects类的导入 from java.util

public class FooClass {
    //...
    public void acceptFoo(Foo obj) {
        //If obj is null, NPE is thrown
        Objects.requireNonNull(obj).bar(); //or better requireNonNull(obj, "obj is null");
    }
    //...
}
于 2015-03-10T05:08:34.377 回答
2

我想说方法 4 是我看过的代码中最通用的习惯用法。但这对我来说总感觉有点臭。它假设 foo == null 与 foo.bar() == false 相同。

这对我来说并不总是正确的。

于 2013-06-25T16:13:10.850 回答
2

方法 4 是我的首选方法。&& 运算符的短路使代码最易读。方法 3,Catching NullPointerException,在大多数情况下不赞成使用简单的 null 检查就足够了。

于 2013-06-25T16:13:19.817 回答
2

对于 java 11+,您可以使用Objects.nonNull(Object obj)

if(nonNull(foo)){ 
//
}
于 2021-02-15T09:58:15.393 回答
1

如果您控制被调用的 API,请考虑使用Guava 的 Optional 类

更多信息在这里。更改您的方法以返回 aOptional<Boolean>而不是 a Boolean

这会通知调用代码它必须考虑 null 的可能性,方法是调用其中一个方便的方法Optional

于 2013-06-25T16:58:03.073 回答
1

更新

我为 Java 开发人员创建了一个 Java 库(Maven 依赖项),以从他们的代码中删除这个 NullPointerException Hell。查看我的存储库。

NullUtil 存储库

Java中处理空值的通用方法

<script src="https://gist.github.com/rcvaram/f1a1b89193baa1de39121386d5f865bc.js"></script>

  1. 如果该对象不为空,我们将执行以下操作。

    一个。我们可以改变对象(I)

    湾。我们可以返回一些东西(O)作为输出而不是改变对象(I)

    C。我们都可以

在这种情况下,我们需要传递一个函数,该函数需要接受作为我们的对象的输入 param(I) 如果我们这样接受,那么我们可以根据需要改变该对象。而且该功能可能是某物(O)。

  1. 如果一个对象为空,那么我们将做以下事情

    一个。我们可能会以自定义的方式抛出异常

    湾。我们可能会退回一些东西。

在这种情况下,对象为空,因此我们需要提供该值,否则我们可能需要抛出异常。

我举两个例子。

  1. 如果我想在字符串中执行修剪,那么该字符串不应该为空。在这种情况下,我们必须额外检查 null 值,否则我们将得到 NullPointerException
public String trimValue(String s){
   return s == null ? null : s.trim();
}
  1. 如果该对象不为空,我想为对象设置一个新值的另一个函数,否则我想抛出一个运行时异常。
public void setTeacherAge(Teacher teacher, int age){
   if (teacher != null){
      teacher.setAge(age);
   } else{
      throw new RuntimeException("teacher is null")
    }
}

根据我的解释,我创建了一个通用方法,它接受值(值可能为 null),如果对象不为 null,则将执行一个函数,如果对象为 null,则将执行另一个供应商函数。

泛型函数

  public <I, O> O setNullCheckExecutor(I value, Function<I, O> nonNullExecutor, Supplier<O> nullExecutor) {
        return value != null ? nonNullExecutor.apply(value) : nullExecutor.get();
    }

所以有了这个通用函数后,我们可以对示例方法 1 执行以下操作。

//To Trim a value
        String trimmedValue = setNullCheckExecutor(value, String::trim, () -> null);

这里,nonNullExecutor 函数是修剪值(使用方法参考)。nullExecutorFunction 将返回 null,因为它是一个标识函数。

2.

// mutate the object if not null otherwise throw a custom message runtime exception instead of NullPointerException
 setNullCheckExecutor(teacher, teacher -> {
            teacher.setAge(19);
            return null;
        }, () -> {
            throw new RuntimeException("Teacher is null");
        });
于 2021-12-02T14:08:00.037 回答
1

正如其他人所说,#4是不使用库方法时的最佳方法。但是,您应该始终将 null 放在比较的左侧,以确保在出现拼写错误时不会意外地将 null 分配给 foo。在这种情况下,编译器会发现错误。

// You meant to do this
if(foo != null){

// But you made a typo like this which will always evaluate to true
if(foo = null)

// Do the comparison in this way
if(null != foo)

// So if you make the mistake in this way the compiler will catch it
if(null = foo){

// obviously the typo is less obvious when doing an equality comparison but it's a good habit either way
if(foo == null){
if(foo =  null){
于 2015-09-11T17:04:11.330 回答
1

如果您要使用双等号“==”进行检查,则使用对象引用检查 null,例如

if(null == obj) 

代替

if(obj == null)

因为如果您输入错误 single equal if(obj = null) 它将返回 true (分配对象返回成功(其值为 'true')。

于 2017-10-06T12:02:30.970 回答
1

您也可以StringUtils.isNoneEmpty("")用于检查是否为空或为空。

于 2017-08-09T11:26:04.720 回答
0

如果您无权访问 commons apache 库,以下可能会正常工作

if(null != foo && foo.bar()) {
//do something
}
于 2013-06-25T16:15:47.217 回答
0

你的最后一个建议是最好的。

if (foo != null && foo.bar()) {
    etc...
}

因为:

  1. 它更容易阅读。
  2. 它是安全的:如果 foo == null,则永远不会执行 foo.bar()。
  3. 它可以防止诸如捕获 NullPointerExceptions 之类的不良做法(大多数情况下是由于代码中的错误)
  4. 它的执行速度应该与其他方法一样快,甚至更快(尽管我认为几乎不可能注意到它)。
于 2013-06-25T16:30:56.773 回答
0
public <T, U> U defaultGet(T supplier, Function<T, U> mapper, U defaultValue) {
        return Optional.ofNullable(supplier).map(mapper).orElse(defaultValue);

    }

如果您更喜欢函数编程,可以创建此函数

于 2021-08-02T19:26:19.563 回答
0

我们可以使用 Object 类的 Object.requireNonNull 静态方法。实现如下

public void someMethod(SomeClass obj) {
    Objects.requireNonNull(obj, "Validation error, obj cannot be null");
}
于 2017-02-06T06:41:40.313 回答
0

简单的一行代码来检查 null :

namVar == null ? codTdoForNul() : codTdoForFul();
于 2017-06-04T06:34:19.440 回答