【问题标题】:How to avoid try with Future fromTry如何避免使用 Future fromTry 进行尝试
【发布时间】:2018-10-31 11:09:13
【问题描述】:

我需要编写一个刷新流并关闭它的未来。这是我尝试过的:

def close(ous: OutputStream) = Future.fromTry(Try {
    try {
      ous.flush()
    } finally {
      ous.close()
    }
  })

看起来很丑。 try{}finally{}Try 内。但我需要 finally 阻止以避免资源泄漏。有没有办法以不那么丑陋的方式重写代码?

【问题讨论】:

标签: scala try-catch finally


【解决方案1】:

Future 已经捕获了返回 Future.failed 的异常,不需要 fromTry 和 block,所以你可以这样做:

Future { out.flush() }.andThen( _=> out.close )

(Future { out.flush() } 将异步刷新流,andThen 将被调用,无论它完成还是失败。

【讨论】:

    【解决方案2】:

    因为您已经在使用Try,所以在结果上使用模式匹配Try{ stream.flush } 并应用Try{ stream.close() }

    例子,

      import java.io.{ByteArrayOutputStream, OutputStream}
      import java.util.Date
      import java.io.ObjectOutputStream
      import scala.concurrent.Future
      import scala.util.Try
      import scala.util.{Failure, Success}
      import scala.concurrent.ExecutionContext.Implicits.global
    
      def doSomeOperation: OutputStream => Future[String] = (outputStream: OutputStream) =>
        withCleanup(outputStream) {
          Future {
            //1/0
            outputStream.toString
          }
        }
    
      def withCleanup(outputStream: OutputStream)(fn: Future[String]): Future[String] = {
    
        val execution = fn
    
        execution onComplete {
          case Success(_) => cleanup(outputStream)
          case Failure(_) => cleanup(outputStream)
        }
    
        execution
      }
    
      def cleanup(outputStream: OutputStream): Try[Unit] = Try {
        outputStream.flush()
        println("flushed")
      } match {
        case _ => Try { 
          outputStream.close()
          println("closed")
        }
      }
    

    然后调用该函数,该函数也将刷新和关闭您的流。

    val stream = new ObjectOutputStream(new ByteArrayOutputStream())    
    stream.writeObject(new Date())
    
    scala> doSomeOperation(stream)
    res18: scala.concurrent.Future[String] = Future(<not completed>)
    flushed
    closed
    

    【讨论】:

    • 这里不做map是不是意味着如果有更早的失败它不会关闭?
    • @AndyHayden 很好。更新以尝试关闭流,即使主执行或 _.flush() 失败
    【解决方案3】:

    我不清楚这是否真的更干净:

    def close(ous: OutputStream) = Future.fromTry(
      val flushed = Try { ous.flush() }
      val closed = Try { ous.close() }
      if (closed.isFailure) closed else flushed  // bubble up the correct error
    )
    

    注意:这几乎等同于this answer,但不完全是。主要是因为 .close 可能会失败,这必须封装在 Try 中。

    【讨论】:

      【解决方案4】:

      我认为这可能是一个选择。

      def close(ous: OutputStream) = Future.fromTry(Try(ous.flush())) andThen {
          case Success(_) => println("do something here")
          case Failure(_) => ous.close()
      }
      

      【讨论】:

      • 它也应该在 Success 上结束(它是 finally)?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多