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.
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.
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
I think what you want is use()
as defined on Closable
.