Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does an each closure over an empty collection run at least once?

Tags:

groovy

I have a function that downloads files from a web server that is sometimes fed an empty collection. In the function I call each on that collection and what I would expect to happen is that the function just exits with the each closure not being run at all. The problem is that it does get run with an empty filename parameter and the creation of the FileOutputStream goes boom when it is fed a directory instead of a file.

def get(String baseUrl, List files, String targetDir) {
    files.each { filename ->
    // Goes BOOM on next line
    def fos = new FileOutputStream(targetDir + File.separator + filename)
    ...
}

Why does Groovy behave like this and what should I do instead?

like image 875
Fylke Avatar asked May 28 '12 09:05

Fylke


1 Answers

It doesn't, so I assume files contains something (like null?)

[].each {
  println "boom"  // This doesn't appear
}

[null].each {
  println "pow!"  // this does
}

Assuming it is nulls in your files List that is causing the issue, you can get rid of them by:

files.findAll().each { filename ->
  def fos = new FileOutputStream( new File( targetDir, filename ) )
  ...

Or of course, make the thing that generates the List not add nulls in the first place

Edit

Actually, it sounds like you have a List with empty strings in it...

The findAll fix should still work, as empty strings evaluate to false under Groovy Truth

Edit 2

As a quick note, you can probably change:

def fos = new FileOutputStream( new File( targetDir, filename ) )
...

to:

new File( targetDir, filename ).withOutputStream { fos ->
  ...

And it will ensure the stream is closed for you :-)

like image 72
tim_yates Avatar answered Oct 03 '22 08:10

tim_yates