在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值做出反应?
答案 0 :(得分:7)
Optional的想法不是要阻止所有NPE。我们的想法是明确API方法可以返回缺少的值,并强制调用者知道并处理它。
当然,如果此方法返回null而不是Optional,您仍然会获得NPE,但这是一个巨大的设计问题。返回Optional的方法应返回Optional(存在或不存在),而不是null。
使用OO语言,使用此对象的方法而不是静态方法访问对象的状态更为自然。
答案 1 :(得分:3)
JB Nizet提供了一个很好的答案,但我将从面向合同的编程的角度展望它。这也称为合同设计。
在可选&lt; T&gt;之前,签订关于被调用者方法的合同的唯一方法可能是返回null
使用Optional&lt; T&gt;,您可以降低NullPointerExceptions的频率。如果你做了&#34;我将使用Optional,如果合适的话#34;签订合同中的合同:
最后一点是为什么它是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()
解决方案仍然感觉更自然。