对于许多开发人员来说,Java 8中引入的可选类型是一个新事物。

是一个getter方法返回可选的<Foo>类型的地方,经典的Foo一个很好的实践?假设该值可以为空。


当前回答

您必须记住,经常被引用的建议来自那些在Java之外几乎没有任何经验的人,他们没有选项类型或函数式编程经验。

所以你要半信半疑。相反,让我们从“良好实践”的角度来看:

好的实践不仅意味着问“我们如何编写新代码?”,还意味着问“现有代码会发生什么?”

在Optional的例子中,我的环境找到了一个良好且易于遵循的答案:

Optional用于在记录中指定可选值: 记录宠物(字符串名称,可选<品种>品种, 可选< ZonedDateTime > dateOfBirth)

这意味着现有的代码是很好的,但是使用记录的代码(即“新代码”)会导致可选的广泛采用。

结果在可读性和可靠性方面取得了圆满的成功。只要停止使用null。

其他回答

在我自己做了一些研究之后,我发现了一些事情,可以建议什么时候这样做合适。最权威的是以下引用自Oracle文章:

需要注意的是,Optional类的目的不是替换每一个空引用。相反,它的目的是帮助设计更容易理解的api,这样通过读取方法的签名,就可以判断是否可以获得可选值。这迫使您主动展开Optional以处理缺少值的情况。”-厌倦了空指针异常?考虑使用Java SE 8的Optional!

我还从Java 8 Optional中找到了这个节选:如何使用它

“Optional并不适用于这种情况,因为它并不能为我们买到任何东西: 在领域模型层(不可序列化) 在dto中(同样的原因) 输入方法的参数 在构造函数参数中

这似乎也提出了一些有效的观点。

我没有发现任何消极的含义或危险信号,表明“Optional”应该避免。我认为一般的想法是,如果它有帮助或提高了API的可用性,就使用它。

我想说,一般来说,对于返回值可以为空的可选类型是个好主意。然而,对于框架,我认为用可选类型替换经典的getter方法会在使用依赖于getter和setter编码约定的框架(例如Hibernate)时带来很多麻烦。

当然,人们会做他们想做的事。但在添加这个功能时,我们确实有一个明确的意图,它不是一个通用的Maybe类型,尽管很多人都希望我们这样做。我们的意图是为库方法返回类型提供一种有限的机制,其中需要一种明确的方式来表示“没有结果”,而使用null极有可能导致错误。

例如,你可能永远不应该将它用于返回结果数组或结果列表的事情;而是返回一个空数组或列表。几乎不应该将它用作某个字段或方法参数。

我认为常规地使用它作为getter的返回值肯定是过度使用的。

可选选项没有错,应该避免它,只是它不是很多人希望的那样,因此我们相当担心过度使用的风险。

(Public service announcement: NEVER call Optional.get unless you can prove it will never be null; instead use one of the safe methods like orElse or ifPresent. In retrospect, we should have called get something like getOrElseThrowNoSuchElementException or something that made it far clearer that this was a highly dangerous method that undermined the whole purpose of Optional in the first place. Lesson learned. (UPDATE: Java 10 has Optional.orElseThrow(), which is semantically equivalent to get(), but whose name is more appropriate.))

如果你正在使用现代序列化器和其他理解Optional的框架,那么我发现这些指导原则在编写实体bean和域层时很有效:

If the serialization layer (usually a DB) allows a null value for a cell in column BAR in table FOO, then the getter Foo.getBar() can return Optional indicating to the developer that this value may reasonably be expected to be null and they should handle this. If the DB guarantees the value will not be null then the getter should not wrap this in an Optional. Foo.bar should be private and not be Optional. There's really no reason for it to be Optional if it is private. The setter Foo.setBar(String bar) should take the type of bar and not Optional. If it's OK to use a null argument then state this in the JavaDoc comment. If it's not OK to use null an IllegalArgumentException or some appropriate business logic is, IMHO, more appropriate. Constructors don't need Optional arguments (for reasons similar to point 3). Generally I only include arguments in the constructor that must be non-null in the serialization database.

为了使上面的更有效,你可能想要编辑你的IDE模板来生成getter和toString(), equals(Obj o)等的相应模板,或者直接使用这些字段(大多数IDE生成器已经处理空值)。

您必须记住,经常被引用的建议来自那些在Java之外几乎没有任何经验的人,他们没有选项类型或函数式编程经验。

所以你要半信半疑。相反,让我们从“良好实践”的角度来看:

好的实践不仅意味着问“我们如何编写新代码?”,还意味着问“现有代码会发生什么?”

在Optional的例子中,我的环境找到了一个良好且易于遵循的答案:

Optional用于在记录中指定可选值: 记录宠物(字符串名称,可选<品种>品种, 可选< ZonedDateTime > dateOfBirth)

这意味着现有的代码是很好的,但是使用记录的代码(即“新代码”)会导致可选的广泛采用。

结果在可读性和可靠性方面取得了圆满的成功。只要停止使用null。