© Adam L. Davis 2016

Adam L. Davis, Learning Groovy, 10.1007/978-1-4842-2117-4_5

5. Coming from Java

Adam L. Davis

(1)New York, USA

Since most readers are already familiar with Java, it would be helpful to compare common Java idioms with the Groovy equivalent.

Default Method Values

One thing that might surprise you coming from Java is that in Groovy you can provide default values for method parameters. For example, let's say you have a fly method with a parameter called text:

1   def fly(String text = "flying") {println text}

This would essentially create two methods behind the scenes (from a Java standpoint):

1   def  fly() {println "flying"}
2   def  fly(String text) {println text}

This can work with any number of parameters as long as the resulting methods do not conflict with other existing methods.

Equals, Hashcode , and More

One of the tedious tasks you must often do in Java is create an equals and a hashCode method for a class. For this purpose, Groovy added the @EqualsAndHashCode annotation. Simply add it to the top of your class (right before the word class) and you’re done.

Likewise, you often want to create a constructor for all of the fields of a class. For this, Groovy has @TupleConstructor. It simply uses the order of the definitions of your fields to also define a constructor. Just add it right before your class definition.

There’s also the @ToString annotation you can add before your class definition for automatically creating a toString() method for your class .

Finally, if you want to have all of these things on your class, just use the @Canonical annotation. You can use Ctrl+T in the groovyConsole to see how this affects the syntax tree.

1   import   groovy.transform.*          
2   @Canonical class Dragon {def name}
3   println new Dragon("Smaug")
4   // prints: Dragon(Smaug)
5   assert new Dragon("").equals(new Dragon(""))
A426440_1_En_5_Figa_HTML.jpg Exercise

Create your own class with multiple properties using these annotations.

Regex Pattern Matching

Groovy greatly simplifies using a pattern to match text using regex (Regular Expressions).

Where in Java you must use the java.util.regex.Pattern class, create an instance and then create a matcher, in Groovy this can all be simplified to one line.

By convention you surround your regex with slashes. This allows you to use special regex syntax without using the tedious double backslash. For example, to determine if something is an e-mail (sort of):

1   def  isEmail = email ==∼ /[w.]+@[w.]+/

The equivalent code in Java would be:

1   Pattern patt = Pattern.compile("[\w.]+@[\w.]+");
2  boolean  isEmail = patt.matches(email);

There's also an operator for creating a Matcher in Groovy:

1   def email = 'mailto:[email protected]'
2   def  mr = email =∼ /[w.]+@[w.]+/
3   if (mr.find()) println mr.group()

This allows you to find regular expressions inside strings and to get sub-groups from a regex.

A426440_1_En_5_Figa_HTML.jpg Exercise

Create a better regex for validating e-mail in Groovy.

Missing Java Syntax

Due to the nature of Groovy’s syntax and some additions to Java’s syntax over the years, Groovy is “missing” a few functions. However, there are other ways to do the same things.

Arrays can be somewhat difficult to work with in Groovy because the Java syntax for creating an array of values does not compile. For example, the following would not compile in Groovy:

1   String[] array = new  String[] {"foo", "bar"};

You should instead use the following syntax (if you must use an array):

1   String[] array = ['foo', 'bar'].toArray()

For a long time, the for (Type item : list) syntax was not supported in Groovy. Instead you have two options: using the in keyword or using the each method with a closure. For example:

1   // for (def item : list)          
2   for (item in list) doStuff(item)
3   list.each { item -> doStuff(item) }

Semicolon Optional

Since the semicolon is optional in Groovy this can sometimes cause line-ending confusion when you’re used to Java. Usually this is not a problem, but when calling multiple methods in a row (using a fluent API, for example), this can cause problems. In this case, you need to end each line with a non-closed operator, such as a dot for example.

For example, let's take an arbitrary fluent API:

1   class  Pie  {
2     def  bake() { this }
3     def  make() { this }
4     def  eat() { this }
5   }
6   def pie = new Pie().
7           make().
8           bake().
9           eat()

If you were to use the typical Java syntax, it might cause a compilation error in Groovy:

1   def pie = new Pie() //Groovy interprets end of line          
2           .make() // huh? what is this?

Where Are Generics?

Groovy supports the syntax of generics but does not enforce them by default. For this reason, you won't see a lot of generics in Groovy code. For example, the following would work fine in Groovy:

1   List<Integer> nums = [1, 2, 3.1415, 'pie']

However, Groovy will enforce generics if you add the @CompileStatic or @TypeChecked annotation to your class or method. For example:

1   import   groovy.transform.*          
2   @CompileStatic
3   class Foo {
4       List<Integer> nums = [1, 2, 3.1415] //error
5   }

This would cause the compilation error "Incompatible generic argument types. Cannot assign java.util.List <java.lang.Number> to: java.util.List <Integer>". Since 3.1415 becomes a java.math.BigDecimal in Groovy, the generic type of the List is automatically determined to be java.lang.Number.

Groovy Numbers

This discussion leads us to decimal numbers , which use BigDecimal by default in Groovy. This allows you do math without rounding errors.

If you want to use double or float, simply follow your number with d or f respectively (as you can also do in Java). For example:

1   def  pie = 3.141592d
A426440_1_En_5_Figa_HTML.jpg Exercise

Try multiplying different number types and determining the class of the result.

Boolean-Resolution

Since Groovy is very similar to Java, but not Java, it's easy to get confused by the differences. A couple of the areas of confusion are boolean-resolution (also called “Groovy truth”) and the Map syntax sugar.

Groovy is much more liberal in what it accepts in a Boolean expression. For example, an empty string and a zero are considered false. So, the following prints out "true" four times:

1   if ("foo") println("true")
2   if (!"") println("true")
3   if (42) println("true")
4   if (! 0) println("true")
A426440_1_En_5_Figb_HTML.jpg Tip

This is sometimes referred to as “Groovy truth”.

Map Syntax

Groovy syntax sugar for Maps allows you use string keys directly, which is often very helpful. However, this can cause confusion when attempting to get the class-type of a map using Groovy's property-accessor syntax sugar (.class refers to the key-value, not getClass()). So you should use the getClass() method directly.

This can also cause confusion when you’re trying to use variables as keys. In this case, you need to surround the variables with parentheses. For example:

1   def  foo = 1
2   def  bar = 2
3   def map = [(foo): bar]

Without the parentheses, foo would resolve to the string "foo".

Summary

In this chapter, you learned about the following Groovy features:

  • You can provide default method values.

  • Various annotations that simplify life in the groovy.transform package.

  • How regular expressions are built into Groovy.

  • You should define arrays differently than Java.

  • How to use unclosed operations when writing a multiline statement.

  • Groovy uses BigDecimal by default for non-integer numbers.

  • Groovy truth.

  • You can use variable keys in the map syntax.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.100.237