Scala尝试最终的最佳实践

时间:2014-11-20 16:27:47

标签: scala exception-handling

我有以下实现,我试图在任何致命异常期间处理正确的资源关闭:

  private def loadPrivateKey(keyPath: String) = {
    def tryReadCertificate(file: File): Try[BufferedReader] = Try { new BufferedReader(new FileReader(file)) }

    def tryLoadPemParser(reader: BufferedReader): Try[PEMParser] = Try { new PEMParser(reader) }

    def createXXX(buffReader: BufferedReader, pemParser: PEMParser) = try {
     ...  
    } finally {
      buffReader.close()
      pemParser.close()
    }
    tryReadCertificate(new File(keyPath, "myKey.pem")) match {
      case Success(buffReader) => tryLoadPemParser(buffReader) match {
        case Success(pemParser) => createXXX(buffReader, pemParser)
        case Failure(fail) =>
      }
      case Failure(fail) =>
    }
  }

我已经看到我的嵌套案例块是一团糟。有一个更好的方法吗?最后,我只想确保关闭BufferedReaderPEMParser

1 个答案:

答案 0 :(得分:0)

您可以使用for-comprehension来清理一些嵌套的case语句,从而重新构建您的代码:

def tryReadCertificate(file: File): Try[BufferedReader] = Try { new BufferedReader(new FileReader(file)) }

def tryLoadPemParser(reader: BufferedReader): Try[PEMParser] = Try { new PEMParser(reader) }

def createXXX(buffReader: BufferedReader, pemParser: PEMParser) = {
  ...
}

val certReaderTry = tryReadCertificate(new File(keyPath, "myKey.pem"))
val pemParserTry = for{
  certReader <- certReaderTry
  pemParser <- tryLoadPemParser(certReader)
} yield {
  createXXX(certReader, pemParser)
  pemParser
}

certReaderTry foreach(_.close)
pemParserTry foreach (_.close)

这样结构化,你只会在你确定已成功打开的东西上结束近距离呼叫。

更好的是,如果您的PEMParser碰巧延伸java.io.Closeable,意味着Try都包裹了Closeable个对象,那么您可以将最后两行换成像这样的一行:

(certReaderTry.toOption ++ pemParserTry.toOption) foreach (_.close)

修改

回应OP的评论:在第一个示例中,如果tryreadCertificate成功,那么certReaderTry将是Success[BufferedReader],因为它成功了,就在其上调用foreach将产生BufferedReader然后将关闭它。如果certReaderTrySuccess,那么(通过for-comp)我们会调用tryLoadPemParser,如果这也成功,我们可以转到createXXX并分配{{ 1}}到tryLoadPemParser pemParserTry。然后,如果valpemParserTry,则Success产生foreach并且我们可以关闭它时会发生同样的事情。根据这个例子,只要那些PEMParser是成功的并且其他意外事件没有发生(例如在Try中)会一直抛出异常,那么你可以保证最后关闭相关代码将完成其工作并关闭这些资源。

<强> EDIT2

如果您希望createXXX中的值来自单独的createXXX,那么您可以执行以下操作:

Try