簡體   English   中英

我如何表達*最終*等同於Scala的嘗試?

[英]How can I express *finally* equivalent for a Scala's Try?

如何使用新的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

實際上,您提出了更復雜的問題 - 資源管理。 事實上,你的代碼應該是這樣的:

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 有關更多信息,請參閱以下鏈接

由於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)。

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._

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM