Wednesday, July 16, 2014

Don't return in a closure for each() in Groovy

I am a Java coder.  All these years I heard so many buzz about functional language, but I never took the dive.  Well, I got some tastes recently. 

We recently switched to use Gradle to manage the project.  I was banning my head for a couple hours yesterday for an odd problem.


boolean isStartedWithList(String str){
  def list=['pre','post']
  list.each {
    if (str.startsWith(it)){
       println 'hit true'
       return true
    }
   }
  println 'hit default false'
  return false
  }  
If you run isStartedWithList('prehistorical'), you will see
hit true
hit default false
The returned value is false. This is because the (first and the second) return only gets you out of the closure, not the method. There are two ways to fix it: to switch back to the traditional for loop, or not to rely on the early exit from the return call.
boolean isStartedWithList(String str){
  def list=['pre','post']
  for (it:list) {
    if (str.startsWith(it)){
       println 'hit true'
       return true
    }
  println 'hit false'
  return false
  }  
boolean isStartedWithList(String str){
  def list=['pre','post']
  result=false;
  list.each {
    result=result||str.startsWtih(it)
   }
  return result
  }  
Both will get you the expected answer. Lessons are learned!

Edit 7/18/2014:

I just learned a even better one using the groovy collection method any
boolean isStartedWithList(String str){
  return ['pre','post'].any{str.startsWith(it)}
}