Sequences are most useful for large data sets, and these datasets are in many cases originated in some kind of a resource like a database cursor or a file. So the underlying resources remains open until the sequence is processed. But if an exception is thrown during processing, the resource might remain open, because the Kotlin Sequence doesn’t implement AutoCloseable!
Java Stream implements AutoCloseable, so if you use the asStream conversion method from the Kotlin standard library, you lose this advantage!
A concrete example is the getResultStream method from JPA. If this method is used, the underlying resource ( a cursor in the database and the Java object representing it) remains open in case of an exception.
Was it simply “forgotten” to implement AutoCloseable in Sequence or is there any reasoning behind it?
Is there a best-practice to work around this limitation? The best that comes to mind is to create an own sequence wrapper type that implements AutoCloseable.
Thank you for your suggestion. I’ve found the [implementation of useLines:
I don’t understand, what bufferd does (since I haven’t found the implementation) and I have no idea how a separate function should be able to close the underlying stream, if the interface to this stream is only the limited Sequence.
That wouldn’t be too bad, but it had the drawback, that I’d need to write all operations that should be performed on the closeable resource into one block. At the moment my repository function converts the Stream to a Sequence, applies a function for building chunks and then returns this decorated sequence for further use.
My idea was to make the (closeable) sequence available for the user and use use in the final destination where the terminal operation of the sequence happens, maybe with a class like this:
class CloseableSequence<T>(
private val stream: Stream<T>
): Sequence<T> by stream.asSequence(), AutoCloseable by stream
But since all Sequence (extension) functions only work on the standard Sequence I’d need to cast before the use block containing the terminal operation – not a particular elegant solution.
@fvasco … yes, I’m about to realize that! JPA offers streams, so would you use instead? Or would you use a reactive streams implementation like Reactor (which has a fromStream function).
At least in my first experiments Kotlin Flow looks really nice! Porting my code from Sequence to Flow was as easy as possible.
However, I’m not sure if it is really the better choice compared to Reactor. Reactor has a lot of fancy methods like bufferUntilChanged, that are not available for Flow today. Other operators like onCompletion are available, but still experimental. The same functionality is an essential functionality included in Reactor (or RxJava) from day one. So, I have to think about Flow a bit, but I thank you for your suggestion in any case!
Some of these fancy operators probably could be easily implemented in the future or by you. There is definitely an advantage tho to using an already well-known library w.r.t. finding issues that people faced online.