There is a use function in kotlin-stdlib (src).
How to use it:
OutputStreamWriter(r.getOutputStream()).use {
// `it` is your OutputStreamWriter
it.write('a')
}
Answer from user2235698 on Stack OverflowThere is a use function in kotlin-stdlib (src).
How to use it:
OutputStreamWriter(r.getOutputStream()).use {
// `it` is your OutputStreamWriter
it.write('a')
}
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.
Concise way to manage resource with exception in kotlin - Language Design - Kotlin Discussions
Try-with-resources: the Kotlin way? - Kotlin Discussions
Try-with-resources or use() - Kotlin Discussions
[SOLVED] Try with resources with `AutoClosable` - Support - Kotlin Discussions
There is no standard solution for this. If you had all of the Closable instances ready at the start, you could use your own self-defined methods to handle them, like this blog post or this repository shows (and here is the discussion on the official forums that led to the latter).
In your case however, where subsequent objects rely on the previous ones, none of these apply like a regular try-with-resources would.
The only thing I can suggest is trying to define helper functions for yourself that hide the nested use calls, and immediately place you in the second/third/nth layer of these resourcs acquisitions, if that's at all possible.
For simplicity I will use A,B and C for the chained autocloseables.
import java.io.Closeable
open class MockCloseable: Closeable {
override fun close() = TODO("Just for compilation")
}
class A: MockCloseable(){
fun makeB(): B = TODO()
}
class B: MockCloseable(){
fun makeC(): C = TODO()
}
class C: MockCloseable()
Using uses
This would look like this:
A().use {a ->
a.makeB().use {b ->
b.makeC().use {c ->
println(c)
}
}
}
Making a chain use function with a wrapper
Definition
class ChainedCloseable<T: Closeable>(val payload: T, val parents: List<Closeable>) {
fun <U> use(block: (T)->U): U {
try {
return block(payload)
} finally {
payload.close()
parents.asReversed().forEach { it.close() }
}
}
fun <U: Closeable> convert(block: (T)->U): ChainedCloseable<U> {
val newPayload = block(payload)
return ChainedCloseable(newPayload, parents + payload)
}
}
fun <T: Closeable, U: Closeable> T.convert(block:(T)->U): ChainedCloseable<U> {
val new = block(this)
}
Usage
A()
.convert(A::makeB)
.convert(B::makeC)
.use { c ->
println(c)
}
This allows you to avoid having to nest deeply, at the cost of creating wrapper objects.
Is there way to write the following but without all the nasty nested brackets?
fun main() {
val file1 = File("file1.txt")
val file2 = File("file2.txt")
file1.inputStream().use { stream1 ->
file2.inputStream().use { stream2 ->
BufferedReader(InputStreamReader(stream1)).use { reader1 ->
BufferedReader(InputStreamReader(stream2)).use { reader2 ->
// Use the file readers here
val line1 = reader1.readLine()
val line2 = reader2.readLine()
println("Line 1 from ${file1.name}: $line1")
println("Line 1 from ${file2.name}: $line2")
}
}
}
}
}Like in C#?
class Program {
static void Main(string[] args) {
string file1 = "file1.txt";
string file2 = "file2.txt";
using (var stream1 = new FileStream(file1, FileMode.Open))
using (var stream2 = new FileStream(file2, FileMode.Open))
using (var reader1 = new StreamReader(stream1))
using (var reader2 = new StreamReader(stream2)) {
// Use the file readers here
string line1 = reader1.ReadLine();
string line2 = reader2.ReadLine();
Console.WriteLine("Line 1 from {0}: {1}", file1, line1);
Console.WriteLine("Line 1 from {0}: {1}", file2, line2);
}
}
}thanks