Because it’s my bag, I recently found myself writing some code that read various .csv files containing data related to similar concepts (why that data is in various .csv files isn’t germane to the story, baby, so just keep reading); that is, each file contained slightly different data but all the data was inter-related. Accordingly, what I did with the data once I read it was both similar and different. For example, regardless of file, first, I had to see if a particular item (in a row) existed elsewhere (i.e. a database); if it did, I then needed to handle its corresponding elements (i.e. the rest of some portion of the row following that element).

Accordingly, I ended up writing a number of bogue methods that had the following pattern:

<pre class="prettyprint"><code>def readr = new CSVReader(new FileReader(new File(filepath)))
def header = true
readr.readAll().each{ csvrow ->
 if(!header){
  def lnid = csvrow[0].trim()
  if(this.isItemAnHGA(lnid)){
   //do different stuff with the row data, such as build domain objects and cache them...
  }
 }
 header = false
}

Note, each hip file contains a header row (full of column names), which describes the data in the following rows; consequently, upon iterating over all the rows in a file, I’ve got a boolean flag to skip the header (that is, the first row). Once the header row is ignored, I then proceed to grab the initial datum, which is always an id; accordingly, I call the isItemAnHGA method to see if this is an item I should process. If that is the case, I then do something with it. That something, of course, varies depending on what file I’m reading.

After repeating this pattern twice, I was left wondering how I could refactor things a bit– clearly, the logic above didn’t need to be rewritten n times for every file I was going to process.

As it turns out, the code that lies within the inner conditional is an copasetic candidate for a closure, which is essentially a block of code that can be executed at a later point (that is, it is not executed when it’s defined). Thus, I can refactor things a bit and define a more generic .csv file reading and initial data validation logic like so:

<pre class="prettyprint"><code>def handleCSV(filepath, closure){
 def readr = new CSVReader(new FileReader(new File(filepath)))
 def header = true
 readr.readAll().each{ csvrow ->
  if(!header){
   def lnid = csvrow[0].trim()
   if(this.isItemAnHGA(lnid)){
    closure.call([csvrow])
   }
  }
  header = false
 }
}

In the code above, note how the method takes a parameter dubbed closure, which is later used inside the conditional. In this case, the closure is passed a parameter, which is the row read from the .csv file (of course, it not being the header!), via the call method.

Now, I can leverage this generic method and pass it a closure that achieves my specialized logic like so:

<pre class="prettyprint"><code>def buildCacheForConsHSCFile(filepath){
 this.handleCSV(filepath){ input ->
  def csv = input[0]
  cacheService.cacheConsHSC(getItem(csv[0], csv[2], csv[4]))
 }
}

In the code above, the handleCSV method is invoked and in this case, Groovy allows you to define the closure parameter inline (remember, because it’s Groovy’s bag, it won’t be invoked immediately, but later (i.e. inside the handleCSV method))– thus, the input parameter passed into the closure (i.e. all the code between the {}’s) is a validated row from a .csv file. In this particular example, I then proceed to cache these items via a cashService.

Closures can be quite helpful in creating reusable code in an elegant manner; in fact, at a high level, they can embody the strategy or command pattern, if you think about it. Closures, however, are a bit more flexible as they don’t require interfaces nor abstract classes to achieve polymorphic behavior. Can you dig it, man?

Want to learn more about Groovy and Grails? Then sign up for ThirstyHead’s Jump into Groovy and Grails course!

Think easyb is the coolest thing since sliced bread? Then come to my

BDD with easyb

course too!

andrew_glover

When Andrew Glover isn't listening to “Funkytown” or “Le Freak” he enjoys speaking on the No Fluff Just Stuff Tour. He also writes articles for multiple online publications including IBM's developerWorks and O'Reilly’s ONJava and ONLamp portals. Andrew is also the co-author of Java Testing Patterns, which was published by Wiley in September 2004; Addison-Wesley’s Continuous Integration; and Manning’s Groovy in Action.

More from this author