如何表示Scala'的*finally*等价物;试一试?

如何表示Scala'的*finally*等价物;试一试?,scala,Scala,如何使用新的TryAPI将以下Java代码转换为Scala public byte[] deflate(byte[] data) { ByteArrayOutputStream outputStream = null; GZIPOutputStream gzipOutputStream = null; try { outputStream = new ByteArrayOutputStream(); gzipOutputStream =

如何使用新的
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
等价物呢?

Scala的
Try
API不应该直接等价于Java中的
Try-catch-finally
构造。事实上,为什么会这样?Scala也内置了
try-catch-finally
构造。您可以像在Java中一样直接使用它<当您需要组合多个可能失败的操作时,需要“代码>尝试”

事实上,您提出了更复杂的问题—资源管理。实际上,您的代码应该是这样的:

try (ByteArrayOutputStream os = new ByteArrayOutputStream(data);
     GZIPOutputStream gzos = new GZIPOutputStream(os)) {
    gzipOutputStream.write(data);
    return outputStream.toByteArray();
} catch (Exception e) {
    ...
}
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)
    } 
}
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()
  }
}
Java中的“try with resources”语言特性会自动关闭在
try
后面括号中指定的所有资源

不幸的是,Scala在库或语言中还没有直接的等价物。但由于Scala更具表现力,您可以手动编写此构造,也可以使用第三方库,我推荐使用第三方库。有关更多信息,请参见以下链接:


因为Try{}块永远不会抛出异常,所以不需要finally语句。此外,对于这个特定场景,您可能应该像其他海报建议的那样使用scala arm

但您可以很容易地将finally方法添加到Try中,以在成功或失败的情况下执行副作用

大概是这样的:

try (ByteArrayOutputStream os = new ByteArrayOutputStream(data);
     GZIPOutputStream gzos = new GZIPOutputStream(os)) {
    gzipOutputStream.write(data);
    return outputStream.toByteArray();
} catch (Exception e) {
    ...
}
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)
    } 
}
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()
  }
}
请注意,按照所有Try方法的精神,如果您的操作引发非致命异常,则不会引发异常,而只是将其捕获为失败

您可以这样使用它:

try (ByteArrayOutputStream os = new ByteArrayOutputStream(data);
     GZIPOutputStream gzos = new GZIPOutputStream(os)) {
    gzipOutputStream.write(data);
    return outputStream.toByteArray();
} catch (Exception e) {
    ...
}
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)
    } 
}
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,那么您将得到一个失败(NullPointerException)。此外,如果close抛出IOException,您将得到一个失败(IOException)

Choppy的Lazy TryClose monad是为这种您想尝试使用资源的场景而设计的。另外,它很懒,所以你可以写东西

以下是您将如何使用它的示例:

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
}
val输出=for{

outputStream可能是您应该使用scala arm的副本。非常有趣……但如果是非致命性的,我不会返回失败,因为这将阻止deflate()返回压缩输出,如果出于任何原因outputStream.close()的话失败…Finally块用于关闭输出流,而不管Try块是否成功。如果关闭ByteArrayOutputStream失败,则会出现严重错误,不返回压缩输出是您最不担心的问题。创建或关闭类似ByteArrayOutputStream的内容会失败的唯一原因是一个OutOfMemoryError,这当然是致命的,在任何情况下都需要抛出。是的,它看起来像是scala arm提供了我想要的功能…我希望它能集成到正式的scala发行版中。