I\'m using a Java-API which heavily uses the Autoclosable-Interface and thus in Java try-with-resources. However in Java you can specify
Method 1: For two resources and using native java resource manager:
Define jUsing()
in Kotlin:
// crossinline version:
inline fun
jUsing(a: A, b: B, crossinline block: (A, B) -> R): R =
J.jUsing(a, b) { c, d -> block(c, d) }
And also Util.jUsing()
in Util.java
:
Note: Below code
is compatible with Java 9+. You can implement it with try-catch-finally
to make it compatible with previous versions. See here for an example.
public static R
jUsing(A a, B b, Function2 block) throws Exception {
try (a; b) {
return block.invoke(a, b);
}
}
(Function2
is kotlin.jvm.functions.Function2
.)
Then use like below:
// Download url to destFile and close streams correctly:
jUsing(URL(url).openStream(), FileOutputStream(destFile), InputStream::transferTo)
Note: Above code
used Java 9+ InputStream.transferTo()
method. See here for a transferTo()
Kotlin alternative that is compatible with previous versions.
Note: You can write Kotlin jUsing()
method more simple using noinline
keyword instead of crossinline
. But I think crossinline
version has more performance:
// noinline version:
inline fun
jUsing(a: A, b: B, noinline block: (A, B) -> R): R =
Util.jUsing(a, b, block)
Method 2: For two resources (and with similar usage to method 1):
Thank @zsmb13's answer for the link
/**
* Based on https://github.com/FelixEngl/KotlinUsings/blob/master/Usings.kt
* and with some changes
*/
inline fun using(a: A, b: B, block: (A, B) -> R): R {
var exception: Throwable? = null
try {
return block(a, b)
} catch (e: Throwable) {
exception = e
throw e
} finally {
if (exception == null) {
a.close()
b.close()
} else {
try {
a.close()
} catch (closeException: Throwable) {
exception.addSuppressed(closeException)
}
try {
b.close()
} catch (closeException: Throwable) {
exception.addSuppressed(closeException)
}
}
}
}
Method 3: For any number of resources (arrayOf(stream1, stream2, ...).use {...}
):
/**
* Based on https://medium.com/@appmattus/effective-kotlin-item-9-prefer-try-with-resources-to-try-finally-aec8c202c30a
* and with a few changes
*/
inline fun Array.use(block: (Array) -> R): R {
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
when (exception) {
null -> forEach { it?.close() }
else -> forEach {
try {
it?.close()
} catch (closeException: Throwable) {
exception.addSuppressed(closeException)
}
}
}
}
}
See referenced link for more details.