Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

try-with-resources / use / multiple resources

Tags:

kotlin

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

try (res1, res2, res3...) {
  ...
}

Do we have a way to use more than one resource? It looks like the well known callback-hell:

val database = Databases.openDatabase(dbFile)

database.use {
  database.createResource(ResourceConfiguration.Builder(resPathName, config).build())

  val resMgr = database.getResourceManager(ResourceManagerConfiguration.Builder(resPathName).build())

  resMgr.use {
    val wtx = resMgr.beginNodeWriteTrx()

    wtx.use {
      wtx.insertSubtreeAsFirstChild(XMLShredder.createStringReader(resFileToStore))
    }
  }
}
like image 518
Johannes Avatar asked Apr 20 '18 14:04

Johannes


People also ask

Can we use multiple resources in try with resources?

We can declare multiple resources in a try block. Try initialization block can have any number of resources resulting in either null or non-null resources. In the below example, we can able to declare multiple resources in the try-with-resources statement.

What is the use of try with resources?

The try -with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try -with-resources statement ensures that each resource is closed at the end of the statement.

What is the advantage of using try with resources statement?

A resource is an object that must be closed once your program is done using it. For example, a File resource or a Socket connection resource. The try-with-resources statement ensures that each resource is closed at the end of the statement execution.

Can we use finally with try with resources?

A try-with-resources block can still have the catch and finally blocks, which will work in the same way as with a traditional try block.


2 Answers

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.

like image 141
zsmb13 Avatar answered Oct 21 '22 03:10

zsmb13


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.

like image 27
jrtapsell Avatar answered Oct 21 '22 03:10

jrtapsell