2014-11-23 66 views
2

https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained的解释是番石榴(和后来的java 8)添加了一个通用类可选,以清除空检查。为什么guava/java使用possible.isPresent()而不是Optional.isPresent(可能)?

如果一个函数返回一个Optional,它需要调用者在使用它之前解开字符串。

这种形式

Optional<String> possible = returnAnAbsentOptional(); 
if(possible.isPresent()){ 
    System.out.println(possible.get()) 
} 

会正常完成。如果returnAnAbsentOptional返回null,我们有一个NPE一遍。

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

+5

我不明白这个问题。如果你通过'null'' Optional',那么你就有一些严重的问题。 – 2014-11-23 12:44:38

回答

3

因为对空值作出反应的正确方法是抛出一个NullPointerException,这就是您在possible == null时调用possible.isPresent()时得到的结果。

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()存在,但name"nameless"。我们得到的结果与我们从未使用Optional的结果相同,并且仅对“缺席”和“现在”使用了空值和非空值。

但是,通过仅使用absent()来表示absent(),我们不正确的代码会抛出NullPointerException

6

可选的想法不是为了防止所有的NPE。我们的想法是明确指出一个API方法可以返回缺少的值,并强制调用者意识到并处理它。

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

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

+0

我并不是问代码是否有大量的设计问题,我正在问具体为什么他们会选择他们所做的。 – 2014-11-23 12:51:47

+2

因为在OO语言中,使用此对象的方法而不是静态方法访问对象的状态会更自然。 – 2014-11-23 12:54:06

+0

@JBNizet我会将该评论添加到答案中 - 这与所提问题有关。 – 2014-11-23 13:03:35

0

面向对象语言的基本设计标准是封装,它表示对象的内部状态应该只对对象本身可见。因此,通常认为通过对象的方法而不是通过静态方法来访问对象的状态是“更清洁”的面向对象设计。在Java中,这可能是一个有趣的问题,因为静态方法也属于一个类,但仍然更加自然。

3

JB Nizet给出了一个很好的答案,但我将从面向契约的编程的未来展开。这也被称为按合同设计。

可选< T>,作出关于被叫方的方法可能返回null合同可以是

  1. 在该方法的javadoc注释中描述的唯一方法之前“这可能返回null如果XYZ”
  2. 把它在一个设计文档,没有人会读
  3. 创建自己的可选类

带有可选< T>,你是减少NullPointerExceptions的频率。如果您在包裹合同中提供了“我将使用可选的合同”合同:

  • 如果您返回一个字符串,则您的调用者不需要执行检查。 (如果调用者为NPE崩溃,那么崩溃不是他们的错,这会成为违反合同的错,这也是为什么一个可选的方法不能返回null,它违背合约只返回非 - 空对象)
  • 如果您返回可选<字符串>,您的呼叫者不能忘记执行可选检查。

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

相关问题