Mat*_*zcz 8 java oop functional-programming scala
在Stackoverflow上已经有很多关于在Java 中使用Optional的正确方法的讨论(像这样的讨论,或者这个)
截至目前,在Java中使用Optional作为类成员被广泛认为是一种代码气味,甚至因故意不实现Serializable接口而气馁.此外,我们应该在DTO,构造函数和方法的输入参数中避免它.从视图中的一切OOP点我迄今大约读可选吸引我的原因.
我的问题是,Scala的FP方面是否会以某种方式改变某些东西我们应该使用Optional?特别是因为Scala 中Optional的实现似乎更丰富.我发现很多文章描述了如何在Scala中使用它,但是没有一篇文章在我应该使用它时何时耗尽主题,何时不应该使用它.
Option字段有用例; 他们本质上并不坏.然而,即使几个成熟的库(例如ScalaTest)定义了具有Option字段的类,后者IMO也往往是代码气味,因为它们经常试图为自己的好处做太多.
在许多情况下,包含可选字段的类型可以容易且有利地由代数数据类型替换.
考虑处理帐户的业务域.一个帐户开始其生命有一天,当一个开放的帐户,但最终可能会被关闭.除其他数据外,账户包含其开放和结束的日期(如果适用).
Option字段以下是使用Option字段的帐户实现:
final case class Account(openedOn: LocalDate, closedOn: Option[LocalDate], ...)
Run Code Online (Sandbox Code Playgroud)
我们还有一个帐户服务,除其他外,还定义了一种close方法:
trait AccountService {
// ...
def close(account: Account): Account
}
Run Code Online (Sandbox Code Playgroud)
出于多种原因,这种方法存在问题.一个问题是Account不是特别高效:因为它closedOn是一个"盒装"类型,你可以说有一个间接级别太多了.而且,Account内存占用空间不太理想:"封闭账户"包含一个非常无趣的价值(None),这是浪费空间.
另一个更严重的问题是该close方法不能在类型级别强制执行参数为"开户"并且结果为"已关闭帐户".您必须编写测试以检查您的实现是否强制执行此业务规则.
Option字段)考虑以下替代设计:
sealed trait Account { ... }
final case class OpenAccount(openedOn: LocalDate, ...) extends Account
final case class ClosedAccount(openedOn: LocalDate, closedOn: LocalDate, ...) extends Account
Run Code Online (Sandbox Code Playgroud)
这个小型ADT可以解决性能问题,但还有更多...您现在可以在类型级别对业务规则进行编码!这是使非法国家无法代表的一个例子(Yaron Minsky的一句话).因此,您服务的API变得更具表现力,更难以滥用:
trait AccountService {
// ...
def close(account: OpenAccount): ClosedAccount
}
Run Code Online (Sandbox Code Playgroud)
这个例子可能足以让你相信第二种方法更可取,并且Option最好避免使用这些字段(或者至少要谨慎使用).
有关消除可选字段以使非法国家无法代表的更多信息,请参阅
scala 选项实现Serializable
的使用OptionScala中强烈建议为空的属性.Option[T]被认为T比前者比后者更安全.
截至目前,在Java中使用Optional作为类成员被广泛认为是代码气味
相反null,scala中的Optional属性的原位存在被认为是代码气味.
尽管Scala是一种功能性语言,但它也是一种促进类型安全的语言.在理想世界中,真正完全类型安全的语言不会有运行时异常,NullpointerException并且Option在Scala中扮演重要角色以避免它.
Option [T]表示属性可以处于null(即None)状态,并强制属性的客户端处理该null场景.因此,Option会向类型系统添加更多信息,并使代码更加类型安全.
使用模式匹配和Monad/Monoid等语言功能,Scala中使用Optional数据类型的经济性在Scala中非常便宜且用户友好,与Java相比.
模式匹配:
optionalVariable match {
case Some(x) => /* handle when variable has a value*/
case None => /* handle when the variable doesn't have a value*/
}
Run Code Online (Sandbox Code Playgroud)
Monad选项:
optionalVariable foreach { x => /* run code when the variable is defined*/ }
optionalVariable map { x => /* map optional type to another type */}
Run Code Online (Sandbox Code Playgroud)
编辑:
Jubobs非常好用,可以用自定义类型替换使用Option.但我认为还有更多的情况,其中可选属性更有意义.为例如:如果帐户对象具有可选的属性,如emailId和phoneNo则选项[T]是因为对于每个组合将是不切实际的,并会导致爆炸类创建自定义类型的一个更好的解决方案.