performance issues with groovy getProperty() method - groovy

suppose that i have a method which has the signature like
def myAction(objet,String propertyName);
i just want to retrieve the property value from objet, i wrote two versions
version 1: I construct the getter method and invoke it on objet
original = propertyName
prefix = original.substring(0,1).toUpperCase()
suffix = original.substring(1,original.length())
methodName = new StringBuilder('get').append(prefix).append(suffix).toString()
value = domain.metaClass.invokeMethod(objet,methodName,null)
version 2: I use directly getProperty method supplied by GroovyObject
value = objet.getProperty(propertyName)
Witch one has better performance?
thinks : )

We can test it to find out using GBench...
I came up with 4 different methods:
#Grab( 'org.gperfutils:gbench:0.4.2-groovy-2.1' )
// Your 'version 1' method
def method1( object, String propertyName ) {
original = propertyName
prefix = original.substring(0,1).toUpperCase()
suffix = original.substring(1,original.length())
methodName = new StringBuilder('get').append(prefix).append(suffix).toString()
assert 'tim' == object.metaClass.invokeMethod(object,methodName,null)
}
// Your 'version 2' method
def method2( object, String propertyName ) {
assert 'tim' == object.getProperty( propertyName )
}
// The same as method 1, but more Groovy
def method3( object, String propertyName ) {
assert 'tim' == object.metaClass.invokeMethod( object, "get${propertyName.capitalize()}",null)
}
// And get the property with the Groovy String templating
def method4( object, String propertyName ) {
assert 'tim' == object."$propertyName"
}
We can then define a class we're going to test:
class Test {
String name = 'tim'
}
def o = new Test()
And then we can run a benchmark over all 4 different versions:
benchmark {
'method1' {
method1( o, 'name' )
}
'method2' {
method2( o, 'name' )
}
'method3' {
method3( o, 'name' )
}
'method4' {
method4( o, 'name' )
}
}.prettyPrint()
On my machine, this prints out:
Environment
===========
* Groovy: 2.1.6
* JVM: Java HotSpot(TM) 64-Bit Server VM (23.25-b01, Oracle Corporation)
* JRE: 1.7.0_25
* Total Memory: 255.125 MB
* Maximum Memory: 1095.125 MB
* OS: Mac OS X (10.8.4, x86_64)
Options
=======
* Warm Up: Auto (- 60 sec)
* CPU Time Measurement: On
user system cpu real
method1 1630 7 1637 1648
method2 429 1 430 435
method3 1368 1 1369 1378
method4 629 1 630 637
So, the fastest is the getProperty one, followed by the object."$propertyName" one, followed by the shorter version of your version 1 method, followed by your original (and slowest) version 1 code
However, I'd argue that method4 is easier to read, and so you have to ask whether it is worth the slight dip in performance

Related

How to Use Groovy to find the INTERSECTION of two lists?

I am trying to retrieve the common items across two lists using Groovy. The following code works just fine, i.e the output from running this code is "DEBUG found in common Items : same". So far so good!
def list1 = ["same", "different"]
def list2 = ["same", "not the same"]
def commonItems = list1.intersect(list2)
for(int i=0; i < commonItems.size(); i++)
{
log.info("DEBUG found in common Items : " + commonItems[i])
}
I hit an issue when I try to apply the above principle to a list of objects - my issue is that the 'commonItems' list does NOT contain the single object I would expect, but is empty. Please note, my custom object 'ErrorWarningDetail' does override compareTo. Can someone see what I am doing wrong / make any suggestions? Thanks in advance!
First of all here is my custom class - note 'CompateTo' just checks the 'Code' field for now.
class ErrorWarningDetail implements Comparable
{
public String Code
public String Description
public String ErrorType
public String State
#Override
int compareTo(Object o) {
int result = Code <=> o.Code
result
}
}
Now here is the code that does the business. I would expect one object to be in 'commonItems' but it is infact empty - what am i doing wrong here? The output of running this is "DEBUG no common items"
def similarONE = new ErrorWarningDetail()
similarONE.Code = "100-1"
def similarTWO =new ErrorWarningDetail()
similarTWO.Code = "100-1"
def completelyDifferent = new ErrorWarningDetail()
completelyDifferent.Code = "697-2"
def List1 = []
def List2 = []
List1.add(similarONE)
List1.add(completelyDifferent)
List2.add(similarTwo)
def commonItems = list1.intersect(list2)
if (commonItems.size() == 0)
{
log.info("DEBUG no common items")
}
Implementing compareTo() is not enough in Java, you should be implementing equals/hashCode instead.
In Groovy there's a handy annotation for that. So, the script down below executes successfully:
import groovy.transform.EqualsAndHashCode
#EqualsAndHashCode( includes = [ 'code' ] )
class ErrorWarningDetail implements Comparable {
String code
String description
String errorType
String state
#Override
int compareTo(Object o) {
code <=> ( o?.code ?: '' )
}
}
def similarONE = new ErrorWarningDetail( code:"100-1" )
def similarTWO = new ErrorWarningDetail( code:"100-1" )
def completelyDifferent = new ErrorWarningDetail( code:"697-2" )
def list1 = [similarONE, completelyDifferent]
def list2 = [similarTWO]
def commonItems = list1.intersect list2
assert 1 == commonItems.size()
P.S. Please, DO NOT name fields starting with Capital letters!
The equals and hashCode are the methods utilized to determine object equality, so the intersect method would rely on those.
The compareTo method is utilized for sorting purposes.
Groovy has some convenient utilities for common tasks in the package groovy.transform
Below is the modified class with the annotations that makes it work as intended.
#EqualsAndHashCode(includes=["Code"])
#ToString(includeFields=true)
class ErrorWarningDetail implements Comparable
{
String Code
String Description
String ErrorType
String State
#Override
int compareTo(Object o) {
Code <=> o?.Code
}
}

Finding list/map of free variable(s) of a closure in groovy

This is my simple groovy script;
def fourtify(String str) {
def clsr = {
str*4
}
return clsr
}
def c = fourtify("aa")
println("binding variables: ${c.getBinding().getVariables()}")
...
All I'm trying to do here is being able to access the free variable "str" using the closure instance to understand how closure works behind the scenes a bit more better. Like, perhaps, Python's locals() method.
Is there a way to do this?
The closure you have defined does not store anything in binding object - it simply returns String passed as str variable, repeated 4 times.
This binding object stores all variables that were defined without specifying their types or using def keyword. It is done via Groovy metaprogramming feature (getProperty and setProperty methods to be more specific). So when you define a variable s like:
def clsr = {
s = str*4
return s
}
then this closure will create a binding with key s and value evaluated from expression str * 4. This binding object is nothing else than a map that is accessed via getProperty and setProperty method. So when Groovy executes s = str * 4 it calls setProperty('s', str * 4) because variable/property s is not defined. If we make a slightly simple change like:
def clsr = {
def s = str*4 // or String s = str * 4
return s
}
then binding s won't be created, because setProperty method does not get executed.
Another comment to your example. If you want to see anything in binding object, you need to call returned closure. In example you have shown above the closure gets returned, but it never gets called. If you do:
def c = fourtify("aa")
c.call()
println("binding variables: ${c.getBinding().getVariables()}")
then your closure gets called and binding object will contain bindings (if any set). Now, if you modify your example to something like this:
def fourtify(String str) {
def clsr = {
def n = 4 // it does not get stored as binding
s = str * n
return s
}
return clsr
}
def c = fourtify("aa")
c.call()
println("binding variables: ${c.getBinding().getVariables()}")
you will see following output in return:
binding variables: [args:[], s:aaaaaaaa]
Hope it helps.
in your example str is a parameter of the method/function fortify
however maybe following example will give you better Closure understanding:
def c={ String s,int x-> return s*x }
println( c.getClass().getSuperclass() ) // groovy.lang.Closure
println( c.getMaximumNumberOfParameters() ) // 2
println( c.getParameterTypes() ) // [class java.lang.String, int]
the locals() Python's function better matches groovy.lang.Script.getBinding()
and here is a simple example with script:
Script scr = new GroovyShell().parse('''
println this.getBinding().getVariables() // print "s" and "x"
z = s*(x+1) // declare a new script-level var "z"
println this.getBinding().getVariables() // print "s", "x", and "z"
return s*x
''')
scr.setBinding( new Binding([
"s":"ab",
"x":4
]) )
println scr.run() // abababab
println scr.getBinding().getVariables() // print "s", "x", and "z"

def vs final def in Groovy

I've written simple test in Groovy using Spock framework
class SimpleSpec extends Specification {
def "should add two numbers"() {
given:
final def a = 3
final b = 4
when:
def c = a + b
then:
c == 7
}
}
Variable a is declared using def and final keywords combination. Variable b is declared using only final keyword.
My question is: what's the difference (if any) between these two declarations? Should one approach be preffed to the other? If so, why?
User daggett ist right, final does not make a local variable final in Groovy. The keyword only has influence on class members. Here is a little illustration:
package de.scrum_master.stackoverflow
import spock.lang.Specification
class MyTest extends Specification {
def "Final local variables can be changed"() {
when:
final def a = 3
final b = 4
final int c = 5
then:
a + b + c == 12
when:
a = b = c = 11
then:
a + b + c == 33
}
final def d = 3
static final e = 4
final int f = 5
def "Class or instance members really are final"() {
expect:
d + e + f == 12
when:
// Compile errors:
// cannot modify final field 'f' outside of constructor.
// cannot modify static final field 'e' outside of static initialization block.
// cannot modify final field 'd' outside of constructor.
d = e = f = 11
then:
d + e + g == 33
}
}
When I switched one of my Spock projects to version 1.3 with Groovy 2.5 and noticed that this test no longer compiles now due to the compiler detecting the reassignment to final local variables. I.e. the inconsistency in Groovy <= 2.4 seems to be fixed.
final variables declared inside the methods are processed as usual variables in groovy
check the class below and the one generated by groovy (2.4.11)
ps: possible the given: section in spock generates code differently...

Remove elements in a string separated by commas in groovy

I am building a string in this way:
def presentationType = "${feedDisplayType}, ${moduleType}, ${cellType}"
What happens is that sometimes the variables has null values, and the resulting string is showing this null values, I have to avoid show null values.
I want to know if there is some way to remove this possible null values in the string or avoid add this when they will be presented.
I know that it is possible and more easy to do with arrays, but I want to do it with strings in a more direct way.
Thanks for any help in advance.
There are 3 options:
1. GString interpolation
def presentationType = "${feedDisplayType != null && !feedDisplayType.isEmpty() ? feedDisplayType + ', ' : ''}${moduleType != null && !moduleType.isEmpty() ? moduleType + ', ' : ''}${cellType != null && !cellType.isEmpty() ? cellType : ''}".toString()
2. Using StringBuilder
def sb = new StringBuilder()
if (feedDisplayType != null && !feedDisplayType.isEmpty()) {
sb.append(feedDisplayType)
sb.append(', ')
}
if (moduleType != null && !moduleType.isEmpty()) {
sb.append(moduleType)
sb.append(', ')
}
if (cellType != null && !cellType.isEmpty()) {
sb.append(cellType)
}
def presentationType = sb.toString()
3. Joining a list with , as a delimiter
def presentationType = [feedDisplayType, moduleType, cellType].findAll { str -> str != null && !str.isEmpty() }.join(', ')
Benchmark
Before going into conclusion let's benchmark all 3 methods using GBench tool:
#Grab(group='org.gperfutils', module='gbench', version='0.4.3-groovy-2.4')
def feedDisplayType = 'test'
def moduleType = null
def cellType = ''
def r = benchmark {
'GString method' {
def presentationType = "${feedDisplayType != null && !feedDisplayType.isEmpty() ? feedDisplayType + ', ' : ''}${moduleType != null && !moduleType.isEmpty() ? moduleType + ', ' : ''}${cellType != null && !cellType.isEmpty() ? cellType : ''}".toString()
}
'StringBuilder method' {
def sb = new StringBuilder()
if (feedDisplayType != null && !feedDisplayType.isEmpty()) {
sb.append(feedDisplayType)
sb.append(', ')
}
if (moduleType != null && !moduleType.isEmpty()) {
sb.append(moduleType)
sb.append(', ')
}
if (cellType != null && !cellType.isEmpty()) {
sb.append(cellType)
}
def presentationType = sb.toString()
}
'Join list method' {
def presentationType = [feedDisplayType, moduleType, cellType].findAll { str -> str != null && !str.isEmpty() }.join(', ')
}
}
r.prettyPrint()
Output
Environment
===========
* Groovy: 2.4.12
* JVM: OpenJDK 64-Bit Server VM (25.171-b10, Oracle Corporation)
* JRE: 1.8.0_171
* Total Memory: 236 MB
* Maximum Memory: 3497 MB
* OS: Linux (4.16.5-200.fc27.x86_64, amd64)
Options
=======
* Warm Up: Auto (- 60 sec)
* CPU Time Measurement: On
user system cpu real
GString method 265 2 267 268
StringBuilder method 72 4 76 77
Join list method 484 3 487 495
Conclusion
If you aim towards highest throughput, StringBuilder method is the best one (77 nanoseconds mean time).
GString method is a few times slower than StringBuilder and it is much less readable due to all condition statements inside a single GString. It is also pretty error prone - it's easy to make a mistake when interpolating String in this case.
Joining list method is the slowest one (only 2 times slower approximately than GString method), but it is the cleanest one. And it is still pretty fast - 495 nanoseconds is acceptable in most cases. Of course optimization depends on specific use case - if you have to execute this part of code million times per second, then using StringBuilder instead makes much more sense.
Benchmark corner cases
To make this example complete let's also take a look at corner cases in benchmarking. We use the same code with different input.
Input:
def feedDisplayType = 'lorem ipsum'
def moduleType = 'dolor sit amet'
def cellType = '123456789'
Output:
user system cpu real
GString method 387 1 388 390
StringBuilder method 170 0 170 175
Join list method 847 6 853 859
Input:
def feedDisplayType = ''
def moduleType = ''
def cellType = ''
Output:
user system cpu real
GString method 237 5 242 242
StringBuilder method 44 0 44 44
Join list method 441 0 441 446
Edit: This answer has been changed as there is a requirement to not print "," for null terms.
Consider:
def feedDisplayType = 'abc'
def moduleType = null
def cellType = 'ijk'
def f = { s, isLast = false ->
def token = s ?: ''
def seperator = (!s || isLast) ? '' : ','
"${token}${seperator}"
}
def presentationType = "${f feedDisplayType}${f moduleType}${f cellType,true}"
assert 'abc,ijk' == presentationType
Note that in function calls, parens are optional in Groovy so ${f x} is equivalent to ${f(x)}. f was originally field in an earlier version, but I've shortened it for brevity.

Difference of two maps in groovy using collectEntries

I am trying to find the difference between values in two maps
#Test
void testCollecEntries() {
def mapOne= ["A":900,"B":2000,"C":1500]
def maptwo = ["A":1000,"D":1500,"B":1500]
def balanceMap = maptwo.collectEntries { key, value-> [key:value-mapOne[key]] }
println balanceMap
}
I am trying to find the difference of values from maptwo with that of the values from mapOne. If the entry doesn't exist i need to ignore. This gives me a null pointer exception.
Appreciate any help.
It will throw NPE because you are looking for key "D" in mapOne which is not available.
You can avoid that by a null safe operation and default value to 0.
def one= [A:900, B:2000, C:1500]
def two = [A:1000, D:1500, B:1500]
def result = two.collectEntries{k,v -> [k, (v - (one[k]?:0))]}
println result
//Print
[A:100, D:1500, B:-500]
In case, you want to consider the common keys then use:
def result = two.collectEntries{k,v -> one[k] ? [k, (v - one[k])] : [:]}
//or
//def result = two.collectEntries{k,v -> (k in one.keySet()) ? [k, (v - one[k])] : [:]}
//Print
[A:100, B:-500]
You could look at this good example: http://groovyconsole.appspot.com/script/364002

Resources