有没有更好的方法来确保资源得到正确发布 - 更好的方法来编写以下代码?
val out: Option[FileOutputStream] = try {
Option(new FileOutputStream(path))
} catch {
case _ => None
}
if (out.isDefined) {
try {
Iterator.continually(in.read).takeWhile(-1 != _).foreach(out.get.write)
} catch {
case e => println(e.getMessage)
} finally {
in.close
out.get.flush()
out.get.close()
}
}
Run Code Online (Sandbox Code Playgroud)
Rex*_*err 20
这样的东西是个好主意,但我会把它变成一个方法:
def cleanly[A,B](resource: => A)(cleanup: A => Unit)(code: A => B): Option[B] = {
try {
val r = resource
try { Some(code(r)) }
finally { cleanup(r) }
} catch {
case e: Exception => None
}
}
Run Code Online (Sandbox Code Playgroud)
(注意我们只捕获一次;如果你真的想要在一个案例中打印一条消息而不是另一个案例,那么你必须像你一样抓住这两个消息).(另请注意,我只捕获异常;捕获Error
也通常是不明智的,因为它几乎不可能从中恢复.)方法的使用方式如下:
cleanly(new FileOutputStream(path))(_.close){ fos =>
Iterator.continually(in.read).takeWhile(_ != -1).foreach(fos.write)
}
Run Code Online (Sandbox Code Playgroud)
因为它返回一个值,所以Some(())
如果它在这里成功了(你可以忽略它).
编辑:为了使它更通用,我真的让它返回一个Either
,所以你得到了例外.像这样:
def cleanly[A,B](resource: => A)(cleanup: A => Unit)(code: A => B): Either[Exception,B] = {
try {
val r = resource
try { Right(code(r)) } finally { cleanup(r) }
}
catch { case e: Exception => Left(e) }
}
Run Code Online (Sandbox Code Playgroud)
现在,如果你得到了Right
,一切都没问题.如果你得到了Left
,你可以选择你的例外.如果你不关心异常,你可以使用.right.toOption
它将它映射到一个选项,或者只是使用.right.map
或者用什么来操作正确的结果只有它存在(就像Option
).(模式匹配是处理Either
s 的有用方法.)