避免!=空语句

微笑、不失礼 提交于 2019-12-06 02:45:19

我经常使用object != null来避免NullPointerException

有没有好的替代方法?

例如:

if (someobject != null) {
    someobject.doCalc();
}

如果不知道对象是否为null ,则可以避免NullPointerException

请注意,接受的答案可能已过期,请参阅https://stackoverflow.com/a/2386013/12943以获取最新的方法。


#1楼

Java 7有一个新的java.util.Objects实用程序类,在该类上有一个requireNonNull()方法。 如果它的参数为null,则所有操作都将引发NullPointerException ,但会稍微清理一下代码。 例:

Objects.requireNonNull(someObject);
someObject.doCalc();

该方法对于检查构造函数中的赋值之前最有用,其中每次使用它可以节省三行代码:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

变成

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}

#2楼

最终,完全解决此问题的唯一方法是使用另一种编程语言:

  • 在Objective-C中,您可以等效于在nil上调用方法,并且绝对不会发生任何事情。 这使得大多数null检查都是不必要的,但会使错误更难以诊断。
  • 在Java派生的语言Nice中 ,有两种所有类型的版本:可能为空的版本和非为空的版本。 您只能在非空类型上调用方法。 通过显式检查null,可以将潜在为null的类型转换为非null的类型。 这样可以更轻松地知道哪些地方需要空检查,哪些地方没有空检查。

#3楼

只是永远不要使用null。 不要这样

在我的课程中,大多数字段和局部变量都具有非null的默认值,并且我在代码的各处添加了合同声明(始终为断言),以确保这是强制执行的(因为它更简洁,比让它更具表达力)作为NPE出现,然后必须解析行号等)。

一旦采用了这种做法,我发现问题似乎已经解决。 您会在开发过程中很早就偶然发现问题,并且意识到自己的弱点。更重要的是,它有助于封装不同模块的关注点,不同模块可以“相互信任”,而不会产生混乱。 if = null else代码if = null else构造!

从长远来看,这是防御性的编程,可以使代码更简洁。 始终对数据进行消毒,例如在此处执行严格的标准,这样问题就会消失。

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

合同就像微型单元测试一样,即使在生产中也总是运行,并且当发生故障时,您知道为什么,而不是随机的NPE,您必须以某种方式弄清楚。


#4楼

Java 8附带了新的java.util.Optional类,可以解决一些问题。 至少可以说这提高了代码的可读性,并且在使用公共API的情况下,API合同对于客户开发人员而言更加清晰。

他们像这样工作:

给定类型的一个可选对象( Fruit )被创建为方法的返回类型。 它可以为空或包含一个Fruit对象:

public static Optional<Fruit> find(String name, List<Fruit> fruits) {
   for (Fruit fruit : fruits) {
      if (fruit.getName().equals(name)) {
         return Optional.of(fruit);
      }
   }
   return Optional.empty();
}

现在看这段代码,我们搜索的列表, Fruitfruits )对于给定的水果如:

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

您可以使用map()运算符对可选对象执行计算或从中提取值。 orElse()允许您为缺少的值提供备用。

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

当然,仍然需要检查空值/空值,但是至少开发人员意识到该值可能为空,并且忘记检查的风险受到限制。

在使用Optional从头构建的API中,无论何时返回值可能为空,并且仅当它不能为null (约定)时才返回普通对象,客户端代码可能会放弃对简单对象返回值的null检查...

当然, Optional也可以用作方法参数,在某些情况下,这可能是比5或10个重载方法更好的指示可选参数的方法。

Optional提供其他方便的方法,如orElse ,允许使用默认值,并ifPresent与工作lambda表达式

我邀请您阅读本文(我写此答案的主要来源),其中很好地解释了有问题的NullPointerException (通常是空指针)以及Optional带来的(部分)解决方案: Java Optional Objects


#5楼

  1. 切勿将变量初始化为null。
  2. 如果无法使用(1),请将所有集合和数组初始化为空的集合/数组。

用您自己的代码执行此操作,可以避免!=空检查。

大多数时候,空检查似乎可以保护集合或数组的循环,因此只需将它们初始化为空,就不需要任何空检查。

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

这样做的开销很小,但是对于更简洁的代码和更少的NullPointerExceptions而言,这是值得的。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!