Ensuring file handle is closed in case of an exception fun readLines(path: String): Stream&lt;String&gt; =
    try {
        Files.lines(Paths.get(path)).use { it }
    } catch (ex: Exception) {
        ex.printStackTrace()
        Stream.empty&lt;String&gt;()
    }


I added .use { it } to tack on try-with-resources like behaviour for autoclosing the file handle (?) in case of exceptions.


Is this required?
Are there better approaches?
Your situation
Use closes the resource at the end of the block (lambda).
This means that the stream is closed before returning it.
The problem with reading lines
The file needs to be closed once you have read the needed lines.
The stream could close the file once the stream last item is reached.
The problem with this approach is that functions like limit, take, splititerator etc. are making it possible that the last item is never reached.
Therefor, you can do two things.
The first option is to let the caller close the file or sequence/stream/whatever you return.
The second option is to close inside your function, but then you need to do all the reading inside the function, so before you return from the function.
Options
You can read everything immediately by storing everything in a list using readlines.
(This means you read the whole file into memory, which means you should not do this for huge, huge, huge files, you almost always can ignore this warning).
fun readLines(path: String): List&lt;String&gt; = try{
    Paths.get(path).toFile().readLines()
} catch(ex: Exception) {
    ex.printStackTrace()
    emptyList&lt;String&gt;()
}

The other approaches work by moving the code you would normally do outside the function inside the function.
For example the forEachLine:
fun forEachLine(path: String, action: (String)-&gt;Unit){
    try{
        Paths.get(path).toFile().forEachLine(action)
    } catch(ex: Exception) {
        ex.printStackTrace()
    }
}

With that function you could rewrite
val t = readLines(&quot;somePath&quot;)
    .filter{ it.startsWith(&quot;ok:&quot;) }
t.forEach{ println(it) }
t.close()

with
forEachLine(&quot;somePath&quot;){
    if(it.startsWith(&quot;ok:&quot;)
        println(it)
}

If you have functions that operates on a sequence of strings, or want more than a simple forEach, you can access the sequence itself by using  useLines, but again move the reading inside the function:
fun useLines(path: String, action: (Sequence&lt;String&gt;)-&gt;Unit){
    try{
        Paths.get(path).toFile().useLines(action)
    } catch(ex: Exception) {
        ex.printStackTrace()
    }
}

Can replace the former example with:
useLines(&quot;somePath&quot;){ lines-&gt;
    lines.filter{ it.startsWith(&quot;ok&quot;) }
       .forEach{ println(&quot;it&quot;) }
} 

NOTE: this function is not for extracting or returning the sequence.
all the functions needs to be done in the lambda,until you come across a terminal operation, an operation that no longer returns a sequence.
NOTE: sequence is the Kotlin-version of streams with lots of benefits.
Is closing required
from the javadoc

&quot;...Generally, only streams whose source is an IO channel (such as those returned by Files.lines(Path, Charset)) will require closing ...&quot;

so yes.
huge files
You should not use readlines on huge files.
What is a huge file?
The bible has around 31,000 lines which can have 20 bytes reference, so 620,000 bytes or roughly 0,5 mb.
The bible has 3,000,000 characters which is roughly 12 mb.
Acording to this post, Android has a memory limit from around 15mb (in the worst case).
This means that reading the bible in it entirely would theoretically be OK.
So, untill you run into problems, this is nothing to worry about.
Edit:
I don't completely know how flatmap in Java excactly works at the moment.
There was a bug that flatmap was not lazy.
This means that calling fileNames.flatMap(::readLines) with the readLines from your code was calculating the complete list before moving on: link.
This bug is fixed, so I don't know what it does at the moment.
If it still works the same way, it always closes the file for you, but it does so because it always parses the complete file.
In every case, if you are returning the Java-stream, calling close on the returning Stream is enough to close the file.
With sequences, this is not possible, as sequences are not closeable (They also don't know about AutoCloseable/Closeable).