我的应用程序的持久层由存储特征和实现类组成。我在这个问题上犹豫不决:fetchFoo(key: Key)
方法应该返回Option[Foo]
,还是如果找不到密钥,他们应该抛出FooNotFound
个例外吗?
为了增加问题的味道,持久层 - 它是用Scala编写的 - 由Java代码调用。处理Java代码中的scala.Option?嗯。
事实上,直到昨天,持久层都是用Java编写的;我刚刚在Scala中重写了它。作为Java代码库,它依赖于异常而不是返回空值;但是现在我遇到了scala.Option,我正在重新考虑。在我看来,Scala不像Java那样迷恋异常。
答案 0 :(得分:4)
我对一般问题的看法是,它取决于密钥的来源。
如果某些用户或不受信任的系统正在输入它们,那么我使用Option
,这样我就可以有意义地表示未知密钥的可能性并适当地处理它。
另一方面,如果密钥来自一个已知系统(这包括嵌入最初来自系统的链接中的密钥之类的东西),并且假设它们是有效的并且存在,我会把它留作运行时异常,由外层的全能型处理。对于链接示例,如果某人出于某种原因手动更改了网址中的密钥,则应将其视为未定义的行为,并且适当的例外情况,IMO。
另一种思考方式是如何处理出现的情况。如果您正在使用Option
并且只是将None
案例委托给一些全面的错误处理,那么异常可能更合适。如果您明确捕获NotFound异常并更改程序流(例如,要求用户重新输入密钥),则使用Option
或已检查的异常(或Scala中的Either
)确保处理这种情况。
关于与Java的集成,一旦Scala运行时库在类路径上可用,Option
就足够容易使用了。或者,Functional Java库中有Option
个实现。在任何情况下,我都会避免使用null
来表示“未找到”。
答案 1 :(得分:2)
在Java中,您可以毫不费力地调用选项的isEmpty
,isDefined
和get
(真正有用的选项方法,例如getOrElse
)是另一回事。 )检查if子句中isDefined
方法的结果应该比检查try-catch块中的异常更快。
答案 2 :(得分:0)
在某些情况下(如你的例子),一个选项很好,“monadic”行为(map,flatMap,filter ...)非常方便,但在其他情况下你需要更多关于问题原因的信息,这可以更好地表达一个例外。现在你可能希望你的错误处理尽可能“统一”,所以我建议使用要么,这会给你一个类似于Option的行为和一个像异常一样的表现力。
在Java中,您只需要一个“解包”Either的辅助函数。如果它找到一个Right(值),它会返回值,如果它找到一个Left(Exception),它会重新抛出它。在此之后,您将恢复正常的Java行为。