Analytics

Monday, February 21, 2011

5 Handy Groovy Shortcuts

Groovy's main advantage over Java programming is the ability for a developer to implement a solution in fewer lines of code. Groovy's idioms produce concise, short, and clean code. Of course, on first look the code may look strange to a Java developer. But once you learn Groovy's shortcuts you realize the value of consciseness and how less noise produces easier maintenance of code. To me, this is simple: "Since there is less code to look at, there is less code to understand. Learn the shortcuts and idioms and produce less code to do more."

Over the last year, I adopted Groovy as an enterprise implementation language. Here are 5 Groovy programming shortcuts that I found to be very handy. They are listed as tests, in the model of TDD.

Spread Dot Operator

The spread dot operator calls a method on every item in a collection. Upon the invocations, it creates a new list from the return items.  So instead of looping through a collection to make a call on each object, use the spread dot operator.

Let's say we want to get the first 3 letters of each username:

    void testSpreadDot() {
      def emails = ["nirav@yahoo.com", "bob@gmail.com", "jacob@msn.com"]
      def firstThreeLetters = emails*.getAt(0..2)
      assertEquals(firstThreeLetters, ["nir", "bob", "jac"])
    } 
This is very useful when utilizing several common design patterns or just plan old polymorphism. You are able to call an interface many times with minimal code.

'as' Operator for BigDecimal conversion

The 'as' keyword in Groovy acts as Cast does in regular Java. A fantastic application of this is for converting strings into BigDecimals. Any application that deals with money inevitably has to read a string such as "54.99" and convert it into a BigDecimal. These strings could come from the UI screen, an Excel spreadsheet, or an external database. With Java, you have to create a new instance, set the scale, do ROUND_UP, ROUND_DOWN. This all becomes non-sense once you use 'as BigDecimal'.

    void testAsBigDecimal() {
      def shirtPriceString = "19.99"
      def shirtPrice = shirtPriceString as BigDecimal
      assertEquals(BigDecimal.class, shirtPrice.class)
      assertEquals(19.99, shirtPrice)
      assertEquals(2, shirtPrice.scale)

      def piString = "3.14159265"
      def pi = piString as BigDecimal
      assertEquals(BigDecimal.class, pi.class)
      assertEquals(3.14159265, pi)
      assertEquals(8, pi.scale)      
    } 
Null and Empty Collection Check

Groovy  has a nifty feature that checks a collection for null or an empty in one shot. So imagine you are checking the database for some trades. If they are present then do some processing. In Java, you would have check two things in the resulting collection: if its not null, and if its not empty. In Groovy, you just check the collection as in an if statement.

    void testNullOrEmptyCollection() {
      def tradeList = ["trade1", "trade2", "trade3"]
      def emptyTradeList = []
      def nullTradeList = null

      if (tradeList) {
        assertTrue(true)
      } else {
        fail("tradeList should return bool true")
      }

      if (emptyTradeList) {
        fail("emptyTradeList should return bool false")
      } else {
        assertTrue(true)
      }

      if (nullTradeList) {
        fail("nullTradeList should return bool false")
      } else {
        assertTrue(true)
      }
    } 
Identity Closure

Groovy is known for its expressive language and concise code. This essentially means that you can express more with less code. When setting attributes in Java, the language forces the developer to restate the variable context in order to access attributes. In groovy, the identity closure retains the object context and relieves you from restating the object again and again. In result, this gives slightly clearer code.

    class Person {
      String firstName
      int age
      String occupation
      String hometown
    }

    void testIdentityClosure() {
      def personMapAttributes = ["firstName": "Nirav", "age":33,
"occupation": "developer", "hometown":"Pittsburgh"]
      Person person = new Person()
      person.identity {
        firstName = personMapAttributes.name
        age = personMapAttributes.age
        occupation = personMapAttributes.occupation
        hometown = personMapAttributes.hometown
      }
      println person.dump()
    } 
Groovy Switch

In Java, switch statements can branch on primitive types. For anything complicated, you have to resort to ugly if/else statements or perhaps polymorphism.  In Groovy, you can switch on any type using the switch closure. The main switch item does not have to be one consistent type either, since Groovy is dynamic.

    void testGroovySwitch() {
      def hello = "hello"
      assertEquals("hello passed in", switchMethod(hello))

      def six = 6
      assertEquals("you passed in something between 5..8", switchMethod(six))

      def person = new Person()
      assertEquals("type person was passed in", switchMethod(person))
    }

    def switchMethod(item) {
      def result = ""
      switch ( item ) {
        case "hello":
          result = "hello passed in"
          break
        case 5..8:
          result = "you passed in something between 5..8"
          break
        case Person:
          result = "type person was passed in"
          break
        default:
          result = "No Matching Case"
      }
    } 
Conclusion

These shortcuts have come in handy for me. Hopefully they will for you as well.

15 comments:

  1. Good stuff....I like the identify hack....

    Thanks for sharing.

    ReplyDelete
  2. rather than using identity {...} you can just pass the map into the constructor: Person person = new Person(personMapAttributes) and it will prepopulate the object

    ReplyDelete
  3. Yes, that is true. Good option. identity would be good if you are updating an existing object.

    ReplyDelete
  4. Looks like identity is like 'with' in delphi or pascal. It is not to set fields only. Try:


    class Person {
    String name
    int age
    void retire() { print('retired') }
    }

    t = new Person()

    t.identity {
    name = 'mathu.'
    age = 123
    age = age + 1
    println(name)
    println(age)
    if (age > 100) {
    print('retired');
    /* retire() // too bad */
    }
    }

    ReplyDelete
  5. Sure, the method identity execute the closure and set the closure's delegate to the object itself. It means that all method calls in the context of the given closure will target the current object, except it's called explicitly on another object.

    ReplyDelete
  6. Very interesting post, thanks! A couple of comments/questions:

    I've always wondered what the real difference is between spread-dot and collect. I mean, def firstThreeLetters = emails.collect{it[0..2]} would work just as well in your example. When would you prefer one over the other?

    Also, .identity can be replaced with .with and it will work as well! Cool beans.

    ReplyDelete
  7. Nirav,
    Thanks for the interesting post.

    ReplyDelete
  8. These short cuts are very interesting from language perspective. Have you thought of maintenance of groovy code in a large scale enterprise applications?

    For example replacing * with something else by mistake in emails*.getAt(0..2) can be easily messed up the whole code until you find out at run-time. The shirtPriceString as BigDecimal
    is just a hack and not provide what you need from BigDecimal in calculation of complex mathematical operations. Groovy is a scripting language that should be used as an addition to java platform and not for replacement for enterprise level software development

    ReplyDelete
  9. @Anonymous - the two main points you made above can be countered strongly with several points:
    - first groovy and grails has been proven widely to scale on large enterprise applications. Go to spring source to find out how. In addition, I am working on grails/groovy on an enterprise level.
    - your example of "replacing * with something else by mistake" is not a characteristic of a language. This mistake can be done in java, or any other language. It is no more likely in groovy than any other language.
    - Run time errors are caught during execution. That is the value of TDD. If you don't practice TDD and unit testing, integration testing, then you have way bigger problems than some syntax errors.
    - When you say "as BigDecimal" is a hack, what do you mean? It has the same abilities of BigDecimal as in Java, as groovy is just an extension of Java. I think you should learn more about that syntax. It has all the abilities for complex calculations.
    - If groovy is only a scripting language, than why is grails an enterprise development framework and why does industry use it? That is a false statement to say groovy is only for scripting, read the mission statement for Groovy and also for grails. Ruby is also scripting language but is is also extended for enterprise development. Should we tell the Rails guys they are way off mark?

    ReplyDelete
  10. I have read your blog its very attractive and impressive. I like it your blog.

    Java Training in Chennai Core Java Training in Chennai Core Java Training in Chennai

    Java Online Training Java Online Training Core Java 8 Training in Chennai java 8 online training JavaEE Training in Chennai Java EE Training in Chennai

    ReplyDelete
  11. Java Training Institutes Java Training Institutes Java EE Training in Chennai Java EE Training in Chennai Java Spring Hibernate Training Institutes in Chennai J2EE Training Institutes in Chennai J2EE Training Institutes in Chennai Core Java Training Institutes in Chennai Core Java Training Institutes in Chennai

    ReplyDelete