1. Introduction
Managed languages, such as those targeting the JVM, automatically handle the most common resource: memory.
However, we need to deal with all kinds of resources, not just memory: files, network connections, streams, windows, etc. And, just like memory, those need to be released when no longer needed.
In this article, we’re going to look at how resources can be managed automatically in Kotlin and how it differs from Java’s try-with-resources construct.
If you want to skip the theory, jump straight to the example.
2. Automatic Resource Management
We can distinguish three different phases when working with resources in Java (pseudocode):
resource = acquireResource() try { useResource(resource) } finally { releaseResource(resource) }
If the language or library is responsible for releasing the resource (the finally part), then we call it Automatic Resource Management. Such feature relieves us from having to remember to free a resource.
Also, since resource management is usually tied to a block scope, if we deal with more than one resource at the same time, they will be always released in the correct order.
In Java, objects that hold a resource and are eligible for automatic resource management implement a specific interface: Closeable for I/O related resources and AutoCloseable.
Also, Java 7 retrofitted the pre-existing Closeable interface to extend AutoCloseable.
Therefore, Kotlin has the same concept of resource holders: that is, objects implementing either Closeable or AutoCloseable.
3. The use Function in Kotlin
To automatically manage resources, some languages have a dedicated construct: Java 7 introduced try-with-resources, for example, while C# has the using keyword.
Sometimes, they offer us a pattern, like RAII in C++. In some other cases, they give us a library method.
Kotlin falls into the latter category.
By design, it doesn’t have a language construct akin to try-with-resources in Java.
Instead, we can find an extension method called use in its standard library.
We’ll look at it in detail later. For now, we just need to know that every resource holder object has the use method that we can invoke.
3.1. How to Use It
A simple example:
val writer = FileWriter("test.txt") writer.use { writer.write("something") }
We can invoke the use function on any object which implements AutoCloseable or Closeable, just as with try-with-resources in Java.
The method takes a lambda expression, executes it and disposes of the resource of (by calling close() on it) whenever execution leaves the block, either normally or with an exception.
So, in this case, after use, the writer is no longer usable, because Kotlin has automatically closed it.
3.2. A Shorter Form
In the example above, for clarity, we used a variable called writer, thus creating a closure.
However, use accepts a lambda expression with a single parameter – the object holding the resource:
FileWriter("test.txt") .use { w -> w.write("something") }
Inside the block, we can also use the implicit variable it:
FileWriter("test.txt") .use { it.write("something") }
So, as we can see, we don’t have to give the object an explicit name. However, it is usually a good idea to be clear rather than writing overly concise code.
3.3. The Definition of use()
Let’s look at the definition of use function in Kotlin, as found in its standard library:
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R
We can see, in the <T : Closeable?, R> part, that use is defined as an extension function on Java’s Closeable interface.
More about extension methods can be found in our introductory article.
Of course, the use function is documented as part of Kotlin’s standard library.
3.4. Closeable vs AutoCloseable
If we pay closer attention to the example from the previous section, we can see that the use function signature is defined only on the Closeable interface. This is because Kotlin’s standard library targets Java 6.
In Java versions before 7, AutoCloseable didn’t exist and, of course, Closeable didn’t extend it.
In practice, classes that implement AutoCloseable but not Closeable are rare. Still, we may encounter one of them.
In that case, we only have to add a dependency on Kotlin’s extensions for Java 7, 8 or whatever version we’re targeting:
<dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jre8</artifactId> <version>1.2.10</version> </dependency>
The latest version of the dependency can be found on Maven Central.
That gives us another use extension function defined on the AutoCloseable interface:
public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R
4. Conclusion
In this tutorial, we’ve seen how a simple extension function in Kotlin’s standard library is all that we need to manage all kinds of resources known to the JVM automatically.
The implementation of all these examples and code snippets can be found in the GitHub project – this is a Maven project, so it should be easy to import and run as it is.