0

I have this example:

def fileLocation = '/path/to/my/file.txt'

new FileReader(fileLocation).withCloseable { fileReader ->
   new BufferedReader(fileReader).withCloseable{ resource ->
      doSomethingWithResource resource
   }
}

Is there any way to achieve this in a more compact way, i.e. without nesting withCloseable()s ? Suppose I need three streams: I would have to nest 3 withCloseable()s, etc.

This example would not work:

new BufferedReader(new FileReader(fileLocation)).withCloseable{ resource ->
   doSomethingWithResource resource
}

as if there is an exception in the outer stream, the inner stream will not be closed.

Note that I could do the following for this over-simplified example:

new File(fileLocation).newReader().withCloseable{ resource ->
   doSomethingWithResource resource
}

but this would not work in case we really need to nest streams. What is the best way to achieve this in groovy?

Edu
  • 160
  • 10
  • your requirement sounds strange. the nested closure will close outer file reader... i mean after `new BufferedReader(fileReader).withCloseable{}` the `fileReader` will be closed – daggett Dec 08 '21 at 17:49
  • I think first the inner stream would be closed, as it is the first finishing, then the outer one. So in this order: `resource.close(); fileReader.close()`. Normally, first the inner one should be closed, then the outer one. – Edu Dec 09 '21 at 07:38
  • if the above is not correct, what would be the groovy equivalent of the following try-with-resources: `try ( FileReader fileReader = new FileReader(fileLocation); BufferedReader resource = new BufferedReader(fileReader) ) { doSomethingWithResource resource }` – Edu Dec 09 '21 at 07:39
  • why not simply `new File(..).withReader{ reader -> somethig reader }` ? – injecteer Dec 09 '21 at 10:09
  • as I mentioned, my example is over-simplified. But in case we really need nest streams (for example some network stream over some file stream over some transforming stream or similar), what would be the correct way to nest this in groovy? So the analogous of the java-way: `try ( FileReader fileReader = new FileReader(fileLocation); BufferedReader resource = new BufferedReader(fileReader) ) { doSomethingWithResource resource }` – Edu Dec 09 '21 at 11:10

1 Answers1

0

Java's try-with-resources is also in Groovy as of version 3.

Your example would become

def fileLocation = '/path/to/my/file.txt'

try ( fileReader = new FileReader(fileLocation)
    bufferedReader = new BufferedReader(fileReader)
) {
    doSomethingWithResource bufferedReader
}

In effect, if you have multiple statements in a try-with-resources, the compiler will generate nested try-finally blocks for each of them.

Closing the BufferedReader will close the underlying FileReader (see 1388602 ). But you're right in the circumstance where the BufferedReader constructor fails with an exception, the FileReader would not be closed. So there's some danger of a resource leak if you do as you said

// RISKY! use try-with-resources instead!
new BufferedReader(new FileReader(fileLocation)).withCloseable{
   resource -> doSomethingWithResource resource
}
Concrete Gannet
  • 551
  • 4
  • 11