If you are using Scala 2.13, you should use the " " object .
In older versions of scala, there is no direct support for the javas try-with-resources construct, but you can pretty easily create your own support by applying a loan template. The following is a simple but not optimal example that is easy to understand. A more correct solution will be given later in this answer:
import java.lang.AutoCloseable def autoClose[A <: AutoCloseable,B]( closeable: A)(fun: (A) โ B): B = { try { fun(closeable) } finally { closeable.close() } }
This defines a reusable method that works almost like a try-with-resource construct in java. It works on two parameters. The first is a subclass of the Autoclosable instance, and the second is a function that takes the same Autoclosable type as the parameter. The return type of the function parameter is used as the return type of the method. The method then executes the function inside try and closes autocomplete in its finally block.
You can use it as follows (here it is used to get the result of findAny () in the stream.
val result: Optional[String] = autoClose(Files.lines(Paths.get("somefile.txt"))) { stream โ stream.findAny() }
In case you want to make a catch exception, you have 2 options.
Add a try / catch block around the call to stream.findAny ().
Or add a catch block to a try block in the autoClose method. Note that this should only be done if the logic inside the catch block can be used from all places where autoClose is called.
Please note that, as Vitaliy Vitrenko points out, this method will swallow an exception from the close method if both the function provided by the client and the close method in AutoCloseable throw an exception. Javas try-with-resources handles this, and we can get autoClose to do this, making it a little more complicated:
def autoClose[A <: AutoCloseable,B]( closeable: A)(fun: (A) โ B): B = { var t: Throwable = null try { fun(closeable) } catch { case funT: Throwable โ t = funT throw t } finally { if (t != null) { try { closeable.close() } catch { case closeT: Throwable โ t.addSuppressed(closeT) throw t } } else { closeable.close() } } }
This works by preserving the potential exception that the client function throws and adding the potential close exception to it as a suppressed exception. This is pretty close to how the oracle explains that try-with-resource actually does this: http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html
However, this is Scala, and many people prefer to program more functionally. In a more functional way, the method should return Try, rather than throw an exception. This avoids the side effect of throwing an exception and makes it clear to the client that the answer may be a mistake that should be handled (as indicated in Stas's answer). In a functional implementation, we would also like to avoid using the var variable, so a naive attempt might be:
// Warning this implementation is not 100% safe, see below def autoCloseTry[A <: AutoCloseable,B]( closeable: A)(fun: (A) โ B): Try[B] = { Try(fun(closeable)).transform( result โ { closeable.close() Success(result) }, funT โ { Try(closeable.close()).transform( _ โ Failure(funT), closeT โ { funT.addSuppressed(closeT) Failure(funT) } ) } ) }
It could be called like this:
val myTry = autoCloseTry(closeable) { resource โ //doSomethingWithTheResource 33 } myTry match { case Success(result) โ doSomethingWithTheResult(result) case Failure(t) โ handleMyExceptions(t) }
Or you can just call .get on myTry to return a result, or throw an exception.
However, as Colmar noted in the commentary, this implementation has drawbacks due to the way the return statement works in scala. Consider the following:
class MyClass extends AutoCloseable { override def close(): Unit = println("Closing!") } def foo: Try[Int] = { autoCloseTry(new MyClass) { _ => return Success(0) } } println(foo)
We expect this to print Closing!, But it is not. The problem here is the explicit expression of the return within the body of the function. It forces the method to skip the logic in the autoCloseTry method and thus simply returns Success (0) without closing the resource.
To solve this problem, we can create a combination of 2 solutions, one of which has a functional API to return Try, but uses the classic implementation based on try / finally blocks:
def autoCloseTry[A <: AutoCloseable,B]( closeable: A)(fun: (A) โ B): Try[B] = { var t: Throwable = null try { Success(fun(closeable)) } catch { case funT: Throwable โ t = funT Failure(t) } finally { if (t != null) { try { closeable.close() } catch { case closeT: Throwable โ t.addSuppressed(closeT) Failure(t) } } else { closeable.close() } } }
This should solve the problem and can be used as on the first try. However, this shows that this is slightly error prone, and the erroneous implementation has been the recommended version in this answer for quite some time. Therefore, if you are not trying to avoid using a large number of libraries, you should consider using this function from the library. I think that there is already one other answer pointing to one, but I assume that there are several libraries that solve this problem in different ways.