I'm new to Scala
and looked at source code of Try::apply
def apply[T](r: => T): Try[T] =
try Success(r) catch {
case NonFatal(e) => Failure(e)
}
It simply catches non-fatal exceptions. But what if I need finally clause? Is it possible to emulate it with Try
in a functional way? I mean something like
try{
//acquire lock
//do some
} finally {
// release lock
}
with
Try{
//acquire lock
//do some
}
//Now how to release?
Something similar was already answered here.
TLTR; There is no standard way to do that with the Try monad.
The usual workaround is something like this:
def use[A <: { def close(): Unit }, B](resource: A)(code: A ⇒ B): B =
try {
code(resource)
} finally {
resource.close()
}
That you can use like:
val path = Paths get "/etc/myfile"
use(Files.newInputStream(path)) { inputStream ⇒
val firstByte = inputStream.read()
....
}
Another approach which is explained here, implies that you "extend" the standard 'Try' by adding an additional method 'withRelease'
implicit class TryOps[A <: { def close(): Unit }](res: Try[A]) {
def withRelease() = res match {
case Success(s) => res.close(); res
case Failure(f) => res.close(); res
}
}
Then,
Try {
val inputStream = Files.newInputStream(path))
...
inputStream
}.withRelease()
Since Try
resolves to a value and it doesn't unwind the stack when something fails, you can simply perform the cleanup operations after Try
has executed. For example:
val someLock = ??? // acquire some lock
val result = Try {
// do something and return a result
}
someLock.release()
If you prefer, you can roll your own helper to keep everything into a single expression:
def withLock[A](f: Lock => A): Try[A] = {
val lock = ??? // acquire the lock
val res = f(lock)
lock.release()
}
and then you can write:
val res = withLock { lock =>
// some operation
}
This is usually refered to as loan pattern.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With