如何使用新的Try
API将以下Java代码翻译成Scala?
public byte[] deflate(byte[] data) {
ByteArrayOutputStream outputStream = null;
GZIPOutputStream gzipOutputStream = null;
try {
outputStream = new ByteArrayOutputStream();
gzipOutputStream = new GZIPOutputStream(outputStream);
gzipOutputStream.write(data);
return outputStream.toByteArray();
catch (Exception e) {
...
} finally {
if (gzipOutputStream != null) gzipOutputStream.close();
}
}
Scala版本应该是这样的......
def deflate(data Array[Byte]): Try[Array[Byte]] = Try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
new GZIPOutputStream(outputStream).write(data)
outputStream.toByteArray
}
...但是如何实现Java的finally
等价物?
答案 0 :(得分:5)
Scala的Try
API不应该是 direct ,等同于Java中的try-catch-finally
构造。的确,它应该是什么原因? Scala也内置了try-catch-finally
构造。您可以像在Java中一样直接使用它。当您需要组合可能失败的多个操作时,需要Try
。
事实上,你提出了更复杂的问题 - 资源管理。事实上,你的代码应该是这样的:
try (ByteArrayOutputStream os = new ByteArrayOutputStream(data);
GZIPOutputStream gzos = new GZIPOutputStream(os)) {
gzipOutputStream.write(data);
return outputStream.toByteArray();
} catch (Exception e) {
...
}
Java中的“try-with-resources”语言功能会自动关闭您在try
之后在括号中指定的所有资源。
不幸的是,Scala在库或语言中没有它的直接等价物。但由于Scala更具表现力,您可以手动编写此构造或使用第三方库,其中我建议使用scala-arm
。有关更多信息,请参阅以下链接:
答案 1 :(得分:4)
由于Try {}块永远不会抛出异常,因此不需要finally语句。此外,对于这种特殊情况,您可能应该使用scala-arm,就像其他海报所建议的那样。
但是你可以轻松地将一个finally方法添加到一个在成功或失败的情况下执行副作用的Try。
这样的事情:
implicit class TryHasFinally[T](val value:Try[T]) extends AnyVal {
import scala.util.control.NonFatal
def Finally(action: => Unit) : Try[T] =
try {
action;
value
} catch {
case NonFatal(cause) => Failure[T](cause)
}
}
请注意,在Try的所有方法的精神中,如果您的操作抛出非致命异常,但只是将其捕获为失败,则不会抛出异常。
您可以这样使用它:
import java.io._
import java.util.zip._
def deflate(data: Array[Byte]): Try[Array[Byte]] = {
var outputStream : ByteArrayOutputStream = null
Try {
outputStream = new ByteArrayOutputStream()
new GZIPOutputStream(outputStream).write(data)
outputStream.toByteArray
} Finally {
outputStream.close()
}
}
请注意,您不必在Finally中检查null,因为如果由于某些不可思议的原因,outputStream为null,您将获得一个Failure(NullPointerException)。此外,如果close抛出IOException,您将收到Failure(IOException)。
答案 2 :(得分:0)
Choppy的Lazy TryClose monad是针对这种需要try-with-resources的场景而制作的。另外,它很懒,所以你可以撰写东西。
以下是如何使用它的示例:
val output = for {
outputStream <- TryClose(new ByteArrayOutputStream())
gzipOutputStream <- TryClose(new GZIPOutputStream(outputStream))
_ <- TryClose.wrap(gzipOutputStream.write(data))
} yield wrap(outputStream.toByteArray())
// Does not actually run anything until you do this:
output.resolve.unwrap match {
case Success(bytes) => // do something with bytes
case Failure(e) => // handle exception
}
此处有更多信息:https://github.com/choppythelumberjack/tryclose
(只需确保导入tryclose._
和tryclose.JavaImplicits._
)