I need to use some Java library, which might throw some exceptions in one method and return error codes in another set of methods. So far it leads to the ugly code like

val txn = mgr.prepareTransaction()
val accessRecord = txn.readByQuery(...)
var state : Either[MyError, Result] = null //
try {
  // do something here
  val result = txn.runCodeWithin(new Callable[Result]() {...})
  if (result == -1) {
    state = Left(CanNotReadRecord)
  } else {
    state = Right(txn.getCachedRecord())
  }
} catch {
  case e: Exception => state = Left(GeneralError(e))
} finally {
  state match {
    case Right(_) => txn.commit();
    case _        => txn.rollback();
  }
}

I mostly interested in getting rid of state as var and ability to check the state in finally block. Please advice.

有帮助吗?

解决方案

Scala 2.10 introduced the Try class, which is a more functional replacement to the use case of Either[Throwable, Result]. It's got all of the usual monad ops (the things that make for-comprehensions work), and some other helpful methods. (check out the docs for Try here)

Here's a possible re-implementation of your code, using Try, and replacing CanNotReadRecord with a CanNotReadRecordException. It should be functionally equivalent to your example, with the exception of that replacement.

def txResults(txn: Transaction): Try[Record] = for {
    result <- Try{ txn.runCodeWithin(...) }
    checked <- result match {
        case -1 => Failure( new CanNotReadRecordException )
        case _ => Success( txn.getCachedRecord )
    }
} yield checked

txResults(txn) match {
    case Success(record) => txn.commit()
    case Failure(e) => txn.rollback() //and maybe handle `e`
}

其他提示

The Scala ARM (Automatic Resource Management) library handles all this sort of thing elegantly and in a completely air-tight manner.

Check it out.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top