为什么guava / java使用possible.isPresent()而不是Optional.isPresent(可能)?

时间:2014-11-23 12:41:02

标签: java guava optional

https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained上解释说,guava(以及后来的java 8)添加了一个泛型类Optional,以便清除空值检查。

如果函数返回Optional,则需要调用者在使用之前解包该字符串。

通常以

的形式完成
Optional<String> possible = returnAnAbsentOptional();
if(possible.isPresent()){
    System.out.println(possible.get())
}

如果returnAnAbsentOptional返回null,我们将重新开始NPE。

我的问题是,为什么Guava / Java使用possible.isPresent()而不是Optional.isPresent(可能),它可以相应地对null值做出反应?

4 个答案:

答案 0 :(得分:7)

Optional的想法不是要阻止所有NPE。我们的想法是明确API方法可以返回缺少的值,并强制调用者知道并处理它。

当然,如果此方法返回null而不是Optional,您仍然会获得NPE,但这是一个巨大的设计问题。返回Optional的方法应返回Optional(存在或不存在),而不是null。

使用OO语言,使用此对象的方法而不是静态方法访问对象的状态更为自然。

答案 1 :(得分:3)

JB Nizet提供了一个很好的答案,但我将从面向合同的编程的角度展望它。这也称为合同设计。

在可选&lt; T&gt;之前,签订关于被调用者方法的合同的唯一方法可能是返回null

  1. 在javadoc注释中描述方法&#34;如果xyz&#34;
  2. ,这可能会返回null
  3. 将其放入设计文件中,没有人会阅读
  4. 创建自己的可选类
  5. 使用Optional&lt; T&gt;,您可以降低NullPointerExceptions的频率。如果你做了&#34;我将使用Optional,如果合适的话#34;签订合同中的合同:

    • 如果您返回字符串,则您的来电者不需要进行检查。 (如果调用者崩溃了NPE,它不是崩溃的错误,那就违反了合同。这就是为什么一个Optional&lt; String&gt;方法不能返回null,它会破坏它的原因它的合同只返回非空对象)
    • 如果您返回Optional&lt; String&gt;,您的来电者将无法进行可选检查。

    最后一点是为什么它是Optional.isPresent()而不是Optional.isPresent(Object)。如果你的方法有可能返回null,那么他们可能会忘记调用后者。 他们不能忘记给前者打电话。

答案 2 :(得分:3)

因为对空值作出反应的正确方法是抛出NullPointerException,这就是possible.isPresent()时拨打possible == null时的结果。

Java作为一种语言允许引用类型的任何值为null。 Java用户在不需要它们时没有null值,并且在他们需要时正确处理它们。当他们失败时,可能会抛出NullPointerException

Optional不是写== null的替代方法。 Optional使用 null的替代方案。如果您选择不使用null,然后再使用null,则表示您已创建错误。

对程序员引入的错误做出反应的正确方法是什么?让我们在示例中尝试您的Optional.isPresent(value)想法:

public abstract class BaseClass {
  static boolean optionalIsPresent(Optional<?> possible) {
    return (possible == null) ? false : possible.isPresent();
    // return possible.isPresent();
  }

  public final String name;

  public Optional<Integer> getID();

  protected BaseClass() {
    if (optionalIsPresent(getID())) {
      name = "number " + getID().get();
    } else {
      name = "nameless";
    }
  }
}

public class DerivedClass extends BaseClass {
  private final int id;

  public DerivedClass(int id) {
    this.id = id;
  }

  public Optional<Integer> getID() {
    return Optional.of(id);
  }
}

这里有一个程序员错误,他们试图在设置之前使用最终字段。

如果optionalIsPresent(null)返回false,则上面的代码执行时没有错误,并且我们有一个行为与我们认为我们指定的行为不同的对象:getID()存在,但{ {1}}是name。我们得到了相同的结果,就好像我们从未在第一个地方使用"nameless"一样,只使用了“absent”和“present”的null和非null值。

但是,仅使用Optional代表absent(),我们的错误代码会引发absent()

答案 3 :(得分:0)

面向对象语言的基本设计标准是封装,它表示对象的内部状态应该只对对象本身可见。因此,它通常被认为是更清洁的&#34;面向对象设计通过对象的方法比通过静态方法访问对象的状态。在Java中,这可能是一个品味问题,因为静态方法也属于一个类,但possible.isPresent()解决方案仍然感觉更自然。