Java vs Groovy vs Scala: A simple example

I’m in the process of learning Scala, and find it interesting to contrast the 3 languages of the title. Java is Java.

Groovy, at least in my mind, is a nicer Java. Cleaner syntax, with more commonly done functions built-in. Also, not too hard to learn if you already know Java. With a few exceptions, you can write Java code, and the Groovy compiler will know what to do with it. Once you learn some Groovy features, you can start taking advantage of them.

Groovy also adds dynamic and meta-programming abilities, which are very powerful features, and can make development quicker. Just make sure you write lots of unit tests.

Scala on the other hand is a new animal. It’s still a JVM language, but is trying to address the weaknesses of Java, provide dynamic typing development speed, and still remain statically typed.

Two things in Scala really help with the above. One is type inferencing, and the other is being able to define types.

One of the biggest complaints about Java is the amount of typing required for defining items, especially when Generics are involved. For example:

// Java version
List<String> myList = new ArrayList<String>();
myList.add("some value")
//Scala version
// Note: Scala uses [] rather than <> for generics.
// < and > are valid in Scala method names, so can't be used in definitions.
val myList = new ArrayList[String]
myList.add("some value")
myList add "some other value"

// of course to make it truly Scala, it would become:
val myList = List("some value", "some other value")

The end result is the same. Both myList will be ArrayLists of String, but much less typing required.

Scala also allows something akin to duck-typing. It isn’t duck typing, but it does allow one to not have to define interfaces on a number of Objects that will be used in a method.

// Java
  public void testMethod(IOutputable someObject) {
    someObject.output();
  }
// Groovy
  def testMethod(someObject) {
     someObject.output() // may throw a MissingMethod exception at runtime, so make sure you test
  }
//Scala
  def testMethod(someObject:{def output()}) = {
    someObject.output()
  }

The above method will take any object that has an output() method defined on it. So, you don’t have to define an interface with an output method on it to pass objects in, but the compiler will also have an error if the testMethod is called passing an object that doesn’t define an output method.

The syntax of Scala will seem weird to a Java developer. There are a number of conventions to get used to, and various other ‘oddities’ about the language that take time to get used to. Here’s an example of the same functionality in all three languages.

//Java - what we're used to seeing
public String buildEpochKey(String... keys) {
  StringBuilder s = new StringBuilder("elem")
  for(String key:keys) {
    if(key != null) {
      s.append(".")
      s.append(key)
    }
  }
  return s.toString().toLowerCase()
}
//Groovy - still fairly straight forward to see what's happening.
// NOTE: .with {} means that any method calls in the curly-braces will be called on
// the object before the .with.
// i.e. addAll, retainAll and join will be called on keys2
def buildEpochKey(String... keys) {
  def keys2 = ["elem"]
  keys2.with {
    addAll(keys)
    retainAll{it != null}
    join(".").toLowerCase()
  }
}
//Scala
// - in the method definition, keys is the variable.
// String* is like Java's String...
// the : after the parenthesis with a type defines the method return type (i.e. String in this case)
def buildEpochKey(keys: String*): String = {
  ("elem" +: keys) filter(_ != null) mkString(".") toLowerCase
}

What was that?!?

  • +: means add the item before the +: to the item after it
  • filter filters a collection based on the closure after it. Filter will pass each item into the closure. If the closure returns true, the item will be added to the new collection, otherwise it won’t.
  • _ in a closure is a shortcut for saying the first parameter passed in
  • mkString is Scala’s version of join. mkString also has a variant that takes delimiters.
  • toLowerCase is just that. A call on the string that is the result of mkString

I suspect the Java code is the most efficient of the 3, as it only loops through the items once. Don’t know if Groovy or Scala are able to optimize away the multiple iterations. And, it’s possible this could be written more efficiently. After all, I’m relatively new to Scala and the whole functional development thing.

So, as you can see, Scala can allow you to be very succinct with the code you write, but it certainly takes some getting used to. Also, I’m finding the Scala IDE plugin for Eclipse is only ok. It allows for debugging, and some basic refactoring, but it seems somewhat slow right now.

It is being improved all the time, but as there isn’t a lot of boilerplate code to type with Scala, I’m not minding the plugin weaknesses that much.

As far as resources for learning Scala, I’m currently reading 2 books. One is Programming in Scala 2nd Edition, and the other is O’Reilly Programming Scala. Programming in Scala 2nd Edition was just released, so it covers all the features added in Scala 2.8.1, and the O’Reilly book appears to be updated when new language releases are made. I can’t find a link to the downloadable PDF for the O’Reilly book, but I was able to find one Googling around.

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply