在上一篇文章中,我概述了对Java 8的Optional 类的实用方法。在这篇文章中,我将研究我们应该如何命名可能返回Optional 的查询方法。
方便的方法命名
考虑一个产生树状数据结构的需求,也许是类似XML DOM的东西。基本的数据结构可能看起来像这样:
public XmlElement {
private final String name;
private final String content;
private final Map<String, String> attributes;
private final List<XmlElement> children;
}
(本文以此为例,但许多其他的数据结构或领域对象也面临着类似的问题,所以不要过于纠结于这个例子的 "XML "性,它无法代表XML的每一个微妙之处。)
这篇文章的关键问题是关于这个类所暴露的便利方法。 使用标准的最佳实践,一个没有孩子的元素应该返回一个空列表,一个没有属性的元素应该返回一个空图。 同样,当没有内容时,我们可以使用空字符串,"":
public XmlElement {
public String getName() {...}
public String getContent() {...}
public Map<String, String> getName() {...}
public List<XmlElement> getChildren() {...}
}
这种方法很好,可以让我们完全查询这个不可变的数据结构。 但如果能有一些额外的方便方法就更好了。 主要考虑的是一个按名称返回属性值的方法,天真的实现是:
public XmlElement {
public String getAttribute(String name) {
return attributes.get(name);
}
}
但是,这个方法可以返回null ,上一篇文章建议不要这样做。不那么天真的实现是:
public XmlElement {
public Optional<String> getAttribute(String name) {
return Optional.ofNullable(attributes.get(name));
}
}
这样做更好,因为不再返回null ,而且现在很清楚有一个失败的情况需要考虑。但是,如果调用代码知道它所要求的数据应该在那里,而且如果不在那里就会抛出一个异常怎么办?
在这种情况下,"标准 "的做法是在上一个方法的结果上使用Optional.orElseThrow() 。这是一个很好的建议。但是,同样的,如果在对orElseThrow() 的相同调用之后,又对新的辅助方法进行了大量的调用,这可能是一个迹象,表明这个方便方法并没有起到应有的作用!因此,也许它本身就值得成为一个辅助方法:
public XmlElement {
public String getAttribute(String name) {
String value = attributes.get(name);
if (value == null) {
throw new IllegalArgumentException(
"Unknown attribute '" + name + "' on element '" + this.name + "'"));
}
return value;
}
}
(注意,这遵循了上一篇文章的建议,在类的方法中使用null ,而不是Optional )。
因此,这对许多用例来说是比较好的,在这些用例中,如果属性缺失,无论如何都是一个失败的案例。也就是说,调用者知道这个属性被定义为强制性的,如果它缺失,必然是一个异常。
但在现实中,有些属性是必须的,有些是可选的。 这就把我们带到了本文的重点,以及针对这种情况的设计方法,还有随之而来的命名问题。 我的建议是有两个方法。
public XmlElement {
// throw exception if no attribute
public String
在这种方法中,有两个方法,如果调用者想在找不到名字时出现异常,可以选择一个方法,如果想处理丢失的情况,可以选择另一个方法。
对这种方法的需求是比较少的--它需要是一个可以以两种方式使用的方法,强制的和可选的。 它还需要是一个会被足够多地调用的API,以使两个辅助方法的价值超过额外的成本。 但是当它确实出现的时候,它需要一个好的命名规则,因为这两个方法不能是重载, 而这就是我在这里的提议:
- 当没有找到时,命名为抛出一个异常的方法
getXxx(String) - 命名返回一个可选的
findXxx(String)的方法
在我看来,当这种情况出现时,强制的情况通常是最常见的,因此它被命名为 "get"。
对于这种 "近似重载",还有其他可能的命名方法,但我已经确定了这个方法,作为我的API的正确平衡。
但是请注意,这并不是建议将所有返回Optional 的方法都命名为findXxx(String) 。只有在适当的时候使用,比如与抛出异常的版本配对时,我认为这才有意义。
总结
本文概述了一种命名方法,当你需要在API上使用重载的方便方法时,通常用于访问一个集合,如地图或列表。它建议添加一个方法,getXxx(String) ,在找不到键的时候抛出一个异常,另一个方法findXxx(String) ,在找不到键的时候返回一个空的可选项。