在scala中使用异常是不好的做法吗?

ope*_*sas 23 error-handling functional-programming scala exception

我已经看过很多次使用Option(对于简单值)或者[List [Error],T]来处理错误的scala代码.

这给了这样的代码

def createApplicationToken(accessToken: AccessToken): Either[List[Error], ApplicationToken] = {

// go to social info provider and fetch information
retrieveProviderInfo(accessToken).fold(
  errors  => Left(errors),
  info    => {
    // try to find user using the info from the provider
    // if it's not there, create user
    User.findOrCreateFromProviderInfo(info).fold(
      errors  => Left(errors),
      user    => {
        // try to create a fresh token and save it to the user
        user.refreshApplicationToken.fold(
          errors  => Left(errors),
          user    => Right(user.token)
        )
      }
    )
  }
)
Run Code Online (Sandbox Code Playgroud)

这会产生一个不太好的代码嵌套,迫使你处理每一步的失败,并迫使你让所有的函数返回一个Either [...]

所以我想知道是否

  • 在scala(或一般的函数式编程)中不鼓励使用异常

  • 使用它们有任何缺点(关于不变性或代码并发性)

  • 异常与某些原则或函数式编程相冲突

  • 你可以想出一个更好的方法来编写给定的例子

-

一旦使用return语句找到错误,就可以通过退出函数来避免嵌套,但是在scala中也不鼓励使用return ...

Tra*_*own 24

以下版本使用的正确投影Either是monad,并且与您的代码完全等效:

def createApplicationToken(accessToken: AccessToken) = for {
   info <- retrieveProviderInfo(accessToken).right
   user <- User.findOrCreateFromProviderInfo(info).right
   refr <- user.refreshApplicationToken.right
} yield refr.token
Run Code Online (Sandbox Code Playgroud)

并且在展示优势方面做得更好Either.

更一般地说,规则与Java中的规则相同:在特殊情况下使用异常.你也许会发现,你改变你的定义特殊的一点,当你在这个风格,如正在开发的,无效的用户输入是不是真的例外,超时的网络请求是不是真的例外,等等.

Either自Scala 2.12以来右偏

您现在可以省略.right,因此以下代码与Scala 2.12相同:

def createApplicationToken(accessToken: AccessToken) = for {
   info <- retrieveProviderInfo(accessToken)
   user <- User.findOrCreateFromProviderInfo(info)
   refr <- user.refreshApplicationToken
} yield refr.token
Run Code Online (Sandbox Code Playgroud)

  • 什么是例外?问,因为你提供了一些不是的例子,一些例外的例子会很好. (3认同)

Seb*_*ber 6

正如 om-nom-nom 所说,我问了一个类似的问题: 在 Scala 中抛出异常,什么是“官方规则”

但这并不是我问过的唯一一个可能让您感兴趣的问题,因为我曾经使用大量样板代码和大量缩进级别进行编码,因为模式匹配等...