My own solution for Kotlin's try-with-resources absence
Asked Answered
L

3

6

Kotlin provides the use function for Closeable objects, but it seems they forgot to consider AutoCloseable (e.g. DB prepared statements) for the try-with-resources full Java equivalent.

I've implemented the next "home-made" solution:

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 next way:

fun countEvents(sc: EventSearchCriteria?): Long {
    return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
        var rs = it.executeQuery()
        rs.next()
        rs.getLong(1)
    }
}

I'm new to Kotlin and I would like to know if I'm missing something important in my own solution that could give me problems/leakages in a production environment.

Longship answered 28/3, 2016 at 10:35 Comment(3)
the reason they don't support AutoClosable out-of-the-box is that they are still to implement Java8 support, as well to support JDK8 classesConscience
You could always copy the source for use and change Closeable to AutoCloseable (see ReadWrite.kt:145-177.Anguish
Consider using java 8 for the pattern. You can find it here https://mcmap.net/q/719176/-try-with-resources-quot-use-quot-extension-function-in-kotlin-does-not-always-workEmilio
G
7

Your implementation will work fine but it's different from a standard try-with-resources implementation. If you want it to work like in Java you should do something like that:

inline fun <T : AutoCloseable, R> trywr(closeable: T, block: (T) -> R): R {
  var currentThrowable: java.lang.Throwable? = null
  try {
    return block(closeable)
  } catch (throwable: Throwable) {
    currentThrowable = throwable as java.lang.Throwable
    throw throwable
  } finally {
    if (currentThrowable != null) {
      try {
        closeable.close()
      } catch (throwable: Throwable) {
        currentThrowable.addSuppressed(throwable)
      }
    } else {
      closeable.close()
    }
  }
}

UPDATE:

As mfulton26 pointed out in his comment kotlin.Throwable doesn't contain addSuppressed(Throwable) method so we have to cast kotlin.Throwable to java.lang.Throwable to make the code work.

Grouping answered 28/3, 2016 at 10:58 Comment(3)
There is no addSuppress(Throwable) method on kotlin.Throwable and you cannot use java.lang.Throwable in a Kotlin try-catch so how does this code compile (other than s/throwble/throwable/)?Anguish
@Anguish I believe its supposed to be Exception instead of Throwable.Hargis
@Anguish Thanks, that's a good point. Updated the code to make it compile.Grouping
M
2

Since Kotlin 1.1, .use has an AutoCloseable implementation.

@SinceKotlin("1.1")
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
@kotlin.internal.InlineOnly
public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
    var exception: Throwable? = null
    try {
        return block(this)
    } catch (e: Throwable) {
        exception = e
        throw e
    } finally {
        this.closeFinally(exception)
    }
}

Copied from source

Mccarver answered 20/5, 2017 at 5:40 Comment(0)
S
0

I think what you want is use() as defined on Closable.

Soul answered 28/3, 2016 at 14:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.