Try-with-resources in Kotlin
Asked Answered
P

5

198

When I tried to write an equivalent of a Java try-with-resources statement in Kotlin, it didn't work for me.

I tried different variations of the following:

try (writer = OutputStreamWriter(r.getOutputStream())) {
    // ...
}

But neither works. Does anyone know what should be used instead?

Apparently Kotlin grammar doesn't include such a construct, but maybe I'm missing something. It defines the grammar for a try block as follows:

try : "try" block catchBlock* finallyBlock?;
Parks answered 17/11, 2014 at 9:48 Comment(0)
T
289

There is a use function in kotlin-stdlib (src).

How to use it:

OutputStreamWriter(r.getOutputStream()).use {
    // `it` is your OutputStreamWriter
    it.write('a')
}
Trapezius answered 17/11, 2014 at 18:34 Comment(6)
I love extension methods so much. So many things you can do and no need for additional language features.Lendlease
Adding to this, there is actually an extension property to obtain an OutputStreamWriter as well: r.outputStream.writer.use { ... }Ailurophobe
Link to the reference doc that demonstrates the use extension: kotlinlang.org/docs/reference/…Eft
How can I use multi "use" in a better way? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } } Anatomize
what about for multi streams? I.e, stdout and stderr ? Java try resource allows multiple streams.Patriotism
Sad this is not multiplatform, but only for JVM, so don't use it if your project is multiplatform docsTryout
D
77

TL;DR: No special syntax, just a function

Kotlin, as opposed to Java, does not have a special syntax for this. Instead, try-with-resources, is offered as the standard library function use.

FileInputStream("filename").use { fis -> //or implicit `it`
   //use stream here
} 

The use implementations

@InlineOnly
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    var closed = false
    try {
        return block(this)
    } catch (e: Exception) {
        closed = true
        try {
            this?.close()
        } catch (closeException: Exception) {
        }
        throw e
    } finally {
        if (!closed) {
            this?.close()
        }
    }
}

This function is defined as a generic extension on all Closeable? types. Closeable is Java's interface that allows try-with-resources as of Java SE7.
The function takes a function literal block which gets executed in a try. Same as with try-with-resources in Java, the Closeable gets closed in a finally.

Also failures happening inside block lead to close executions, where possible exceptions are literally "suppressed" by just ignoring them. This is different from try-with-resources, because such exceptions can be requested in Java‘s solution.

How to use it

The use extension is available on any Closeable type, i.e. streams, readers and so on.

FileInputStream("filename").use {
   //use your stream by referring to `it` or explicitly give a name.
} 

The part in curly brackets is what becomes block in use (a lambda is passed as an argument here). After the block is done, you can be sure that FileInputStream has been closed.

Doctrinal answered 20/10, 2017 at 6:40 Comment(1)
What about multiple resources?Honeysuckle
L
16

Edit: The following response is still valid for Kotlin 1.0.x. For Kotlin 1.1, there is support a standard library that targets Java 8 to support closable resource pattern.

For other classes that do not support the "use" function, I have done the following homemade try-with-resources:

package info.macias.kotlin

inline fun <T:AutoCloseable,R> trywr(closeable: T, block: (T) -> R): R {
    try {
        return block(closeable);
    } finally {
        closeable.close()
    }
}

Then you can use it the following way:

fun countEvents(sc: EventSearchCriteria?): Long {
    return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
        var rs = it.executeQuery()
        rs.next()
        rs.getLong(1)
    }
}
Laliberte answered 28/3, 2016 at 10:21 Comment(1)
This does not deal properly with exceptions thrown from the finally clause, which is one of the reasons try-with-resources was added to Java. This is just a simple try/finally blockIncised
T
2

I will highly recommend to use AutoCloseable for classes.

AutoCloseable object is called automatically when exiting a try-with-resources block for which the object has been declared in the resource specification header.

Example:

class Resource : AutoCloseable {
    fun op1() = println("op1")
    override fun close() = println("close up.")
}

in main function:

Resource().use {
    it.op1()
}

Output:

> op1
close up.
Torrez answered 21/12, 2020 at 7:28 Comment(0)
E
1

Since this StackOverflow post is near the top of the current search results for "kotlin closeable example," and yet none of the other answers (nor the official docs) clearly explain how to extend Closeable (a.k.a. java.io.Closeable), I thought I'd add an example of how to make your own class that extends Closeable. It goes like this:

import java.io.Closeable

class MyServer : Closeable {
    override fun close() {
        println("hello world")
    }
}

And then to use it:

fun main() {
    val s = MyServer()
    s.use {
        println("begin")
    }
    println("end")
}

See this example in the Kotlin Playground here.

Epizootic answered 13/4, 2020 at 16:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.