Search

Dark theme | Light theme
Showing posts with label GroovyGoodness:Beginner. Show all posts
Showing posts with label GroovyGoodness:Beginner. Show all posts

June 28, 2022

Groovy Goodness: Using The Switch Expression

In a previous (old) post we learned how Groovy supports different classifiers for a switch case statement. Since Groovy 4 we can use switch also as an expression. This means the switch statement returns a value without having to use return. Instead of using a colon (:) and break we use the -> notation for a case. We specify the value that the switch expressions returns after ->. When we need a code block we simply put the code between curly braces ({...}).

In the following example we use the switch expression with different case statements:

def testSwitch(val) {
    switch (val) {
        case 52 -> 'Number value match'
        case "Groovy 4" -> 'String value match'
        case ~/^Switch.*Groovy$/ -> 'Pattern match'
        case BigInteger -> 'Class isInstance'
        case 60..90 -> 'Range contains'
        case [21, 'test', 9.12] -> 'List contains'
        case 42.056 -> 'Object equals'
        case { it instanceof Integer && it < 50 } -> 'Closure boolean'
        case [groovy: 'Rocks!', version: '1.7.6'] -> "Map contains key '$val'"
        default -> 'Default'
    } 
}

assert testSwitch(52) == 'Number value match'
assert testSwitch("Groovy 4") == 'String value match'
assert testSwitch("Switch to Groovy") == 'Pattern match'
assert testSwitch(42G) == 'Class isInstance'
assert testSwitch(70) == 'Range contains'
assert testSwitch('test') == 'List contains'
assert testSwitch(42.056) == 'Object equals'
assert testSwitch(20) == 'Closure boolean' 
assert testSwitch('groovy') == "Map contains key 'groovy'"
assert testSwitch('default') == 'Default'

Written with Groovy 4.0.3.

June 13, 2018

Groovy Goodness: Truncate And Round BigDecimal Values

Groovy 2.5.0 adds round and truncate methods to the BigDecimal class. These methods were already available on Double and Float classes. The methods can take an argument to denote the number of decimals the rounding or truncating must be applied to.

In the following example we see the methods with and without arguments:

def bigDecimal = 42.576135

// Groovy uses BigDecimal for decimal 
// numbers by default.
assert bigDecimal.class.name == 'java.math.BigDecimal'

assert bigDecimal.round() == 43
assert bigDecimal.round(2) == 42.58

assert bigDecimal.trunc() == 42
assert bigDecimal.trunc(2) == 42.57

Written with Groovy 2.5.0.

January 28, 2015

Groovy Goodness: Pop And Push Items In a List

Groovy adds the pop and push methods to the List class. With the pop method we remove the last element of the list. And with the push method we add an element to the end of the list.

def list = ['Groovy', 'is', 'great!']

// Remove last item from list
// with pop().
assert list.pop() == 'great!'
assert list == ['Groovy', 'is']

// Remove last item
// which is now 'is'.
list.pop()

// Add new item to end of
// the list (equivalent for add()).
list.push('rocks!')

assert list == ['Groovy', 'rocks!']

Code written with Groovy 2.4.

September 9, 2013

Groovy Goodness: Check if a String Only Contains Whitespaces

In Groovy we can check if a String value only contains whitespaces with the isAllWhitespace() method. The method checks for spaces, but also takes into account tab and newline characters as whitespace.

assert ''.allWhitespace
assert '  '.allWhitespace
assert '\t '.allWhitespace
assert ' \r\n '.allWhitespace

assert !'mrhaki'.allWhitespace

October 9, 2012

Groovy Goodness: Getting the First and Last Element of an Iterable

Since Groovy 1.8.7 we can use the first() and last() methods on Iterable objects. With the first() method we get the first element and with the last() method we get the last element:

def list = 0..100

assert list.first() == 0
assert list.last() == 100

def abc = 'abc' as Character[]

assert abc.first() == 'a'
assert abc.last() == 'c'

def s = ['Groovy', 'Gradle', 'Grails', 'Rocks'] as Set

assert s.first() == 'Groovy'
assert s.last() == 'Rocks'

(Written with Groovy 2.0.5)

September 19, 2011

Groovy Goodness: Collect on Nested Collections

The collect() method has been around in Groovy for a long time and it is very useful. With the collect() method we can iterate through a collection and transform each element with a Closure to another value. To apply a transformation to collections in collections we can use the collectAll() method. Since Groovy 1.8.1 the collectAll() method is deprecated in favor of the new collectNested() method. So with collectNested() we can transform elements in a collection and even in nested collections and the result will be a collection (with nested collections) with transformed elements.
We can pass an initial collection to the method to which the transformed elements are added.

def list = [10, 20, [1, 2, [25, 50]], ['Groovy']]

assert list.collectNested { it * 2 } == [20, 40, [2, 4, [50, 100]], ['GroovyGroovy']]
assert list.collectNested(['1.8.1', [0]]) { it * 2 } == ['1.8.1', [0], 20, 40, [2, 4, [50, 100]], ['GroovyGroovy']]
assert list.collectNested([]) { it * 2 } == [20, 40, [2, 4, [50, 100]], ['GroovyGroovy']]

// Simple collect will duplicate the nested collection instead
// of elements in the nested collection.
assert list.collect { it * 2 } == [20, 40, [1, 2, [25, 50], 1, 2, [25, 50]], ['Groovy', 'Groovy']]

September 14, 2011

Groovy Goodness: Take and Drop Items from a List

When working with List object we get a lot of nice and useful methods we can use in Groovy. Since Groovy 1.8.1 we can use the methods take() and drop(). With the take() method we get items from the beginning of the List. We pass the number of items we want as an argument to the method.

To remove items from the beginning of the List we can use the drop() method. Here we pass the number of items we want to drop as an argument to the method. Please keep in mind the original list is not changed, the result of the drop() method is a new list.

def list = ['Simple', 'list', 'with', 5, 'items']

assert list.take(1) == ['Simple']
assert list.take(2) == ['Simple', 'list']
assert list.take(0) == []
// Whole list, because we take more items then the size of list
assert list.take(6) == ['Simple', 'list', 'with', 5, 'items']

assert list.drop(1) == ['list', 'with', 5, 'items']
assert list.drop(3) == [5, 'items']
assert list.drop(5) == []
assert list.drop(0) == ['Simple', 'list', 'with', 5, 'items']
assert list == ['Simple', 'list', 'with', 5, 'items']

// After reading Tim Yates' comment I have added 
// more samples showing drop() and take() also work on
// Maps, Iterators, CharSequences and arrays.
def array = ['Rock on!', 'Groovy baby!'] as String[]
assert array.take(1) == ['Rock on!'] as String[]
assert array.drop(1) == ['Groovy baby!'] as String[]

def range = 0..10
assert range.take(2) == [0,1]
assert range.take(4) == 0..3
assert range.drop(5) == 5..10

def map = [1: 'one', 2: 'two', 3: 'three']
assert map.take(2) == [1: 'one', 2: 'two']
assert map.drop(2) == [3: 'three']
assert map.drop(3) == [:]

def s = 'Hello Groovy world!'
assert s.take(5) == 'Hello'
assert s.drop(6) == 'Groovy world!'

May 24, 2011

Groovy Goodness: Canonical Annotation to Create Mutable Class

With Groovy 1.8 we get a lot of AST transformations. We can combine @ToString, @EqualsAndHashCode and @TupleConstructor with the @Canonical annotation. This annotation will do all the transformations at once. If we want to customize one of the AST transformations, we add the annotation with configuration parameters extra after @Canonical.

import groovy.transform.*

@Canonical
class Building {
    String name
    int floors
    boolean officeSpace
}

// Constructors are added.
def officeSpace = new Building('Initech office', 1, true)

// toString() added.
assert officeSpace.toString() == 'Building(Initech office, 1, true)'

// Default values are used if constructor
// arguments are not assigned.
def theOffice = new Building('Wernham Hogg Paper Company')
assert theOffice.floors == 0
theOffice.officeSpace = true

def anotherOfficeSpace = new Building(name: 'Initech office', floors: 1, officeSpace: true)

// equals() method is added.
assert anotherOfficeSpace == officeSpace

// equals() and hashCode() are added, so duplicate is not in Set.
def offices = [officeSpace, anotherOfficeSpace, theOffice] as Set  
assert offices.size() == 2 
assert offices.name.join(',') == 'Initech office,Wernham Hogg Paper Company'

@Canonical
@ToString(excludes='age')  // Customize one of the transformations.
class Person {
    String name
    int age
}

def mrhaki = new Person('mrhaki', 37)
assert mrhaki.toString() == 'Person(mrhaki)'

December 16, 2010

Groovy Goodness: Convert Date to Calendar

In Groovy version 1.7.6 we can convert a Date to a Calendar with the toCalendar() method. The toCalendar() method is added to the Date class by Groovy.

import static java.util.Calendar.*

def date = new Date()
date.set year: 2010, month: 11, date: 16

def calendar = date.toCalendar()

assert calendar[YEAR] == 2010
assert calendar[MONTH] == Calendar.DECEMBER
assert calendar[DATE] == 16
assert calendar.format('dd-MM-yyyy') == '16-12-2010'
assert calendar in Calendar

November 29, 2010

Groovy Goodness: String Continuation

Groovy makes writing concise code easy,. We can use the continuation character (\) in a String to split up the definition over multiple lines.

def name ='mrhaki'

def s = "This is not a multiline\
 String, $name, but the continuation\
 character (\\) makes it more readable."
        
assert 'This is not a multiline String, mrhaki, but the continuation character (\\) makes it more readable.' == s

July 1, 2010

Groovy Goodness: Clear Time Portion of a Date

Working with dates in Groovy is easy. We get a lot of extra functionality compared to the standard Java Date class. One of the extra methods added to the Date class since Groovy 1.6.8 is clearTime(). With clearTime() we reset the time portion of a date to 12 o'clock midnight. This makes it easier to compare dates if we only are interested in the date, month, year parts.

// Create new date.
def d = new Date(year: 2010, month: Calendar.JULY, date: 1, 
                                hours: 7, minutes: 12, seconds: 0)

assert '7/1/10 7:12:00 AM' == d.dateTimeString

// Reset time portion of the date.
d.clearTime()

assert '7/1/10 12:00:00 AM' == d.dateTimeString

June 14, 2010

Groovy Goodness: Getting Head And Tail From an Array of Objects

We could already use the head() and tail() methods on Collection objects in Groovy, but in Groovy 1.7.3 we can use them on Object arrays as well.

String[] stringArray = ['Groovy', 'Grails', 'Spock']

assert 'Groovy' == stringArray.head()
assert ['Grails', 'Spock'] == stringArray.tail()
assert 'Groovy' == stringArray.first()
assert 'Spock' == stringArray.last()

Groovy Goodness: Use the set Method to Define a Date or Calendar Value

In a previous post we learned about the new subscript operator support in Groovy 1.7.3 for setting Date or Calendar values. But we have other new ways in Groovy 1.7.3: we can use a set() method to set the values. The method accepts a Map with the following keys: year, month, date, hourOfDay, minute and second. The keys are used to set the according values of the Date or Calendar object.

import static java.util.Calendar.*

def cal = Calendar.instance
cal.set(year: 2010, month: JULY, date: 9)

assert 'Birthday @ 2010-7-9' == 'Birthday @ ' + cal.format('yyyy-M-d')
assert FRIDAY == cal[DAY_OF_WEEK]

def date = new Date()
date.set(hourOfDay: 12, minute: 0, second: 0, year: 2010, month: JUNE, date: 1)

assert '12:00:00' == date.format('HH:mm:ss')
assert 2010 == date[YEAR]
assert JUNE == date[MONTH]
assert 1 == date.getAt(DATE)

Groovy Goodness: Setting Date and Calendar Values with Subscript Operators

In Groovy 1.7.3 we have some new ways to set the value of Date or Calendar objects. We can for example use the subscript operators (getAt() and putAt() methods) to define value for fields or get the value from a field. The fields are the Calendar constants like Calendar.YEAR, Calendar.DATE.

import static java.util.Calendar.*

def date = new Date()
// Set value with subscript operator
date[YEAR] = 2010
date[MONTH] = JUNE
date[DATE] = 14

assert 110 == date.year
assert 5 == date.month
assert 14 == date.date

// Get value with subscript operator
assert 2010 == date[YEAR]  
assert JUNE == date[MONTH]
assert 14 == date[DATE]


def cal = Calendar.instance
// Set value with subscript operator
cal[YEAR] = 2000
cal[MONTH] = DECEMBER
cal[DATE] = 25

assert '2000-12-25' == cal.format('yyyy-MM-dd')
assert 2000 == cal[YEAR]  // Get value with subscript operator

Groovy Goodness: Expand or Unexpand Space or Tab Delimited Text

Groovy 1.7.3 adds new functionality to the String class. For example we can use the expand() method to expand tabs in a String to spaces with a default tab stop size of 8. We can use a parameter to use a different tab stop size. But we can also go the other way around.

So if we have a tabular text based on spaces we can convert the String to a tab separated String. Here the default tab stop size is also 8, but we can use the parameter to define a different tab stop size.

// Simple ruler to display 0 up to 30
def ruler = (0..30).inject('\n') { result, c -> 
    result += (c % 10) 
}

def stringWithTabs = 'Groovy\tGrails\tGriffon'

println ruler
println stringWithTabs.expand()  // default tab stop is 8
println stringWithTabs.expand(10)  // tab stop is 10

// Output:
// 0123456789012345678901234567890
// Groovy  Grails  Griffon
/ /Groovy    Grails    Griffon

assert 'Groovy  Grails  Griffon' == stringWithTabs.expand()
assert 'Groovy    Grails    Griffon' == stringWithTabs.expand(10)


def stringWithSpaces = 'Hubert  Klein   Ikkink'
def stringWithSpaces10 = 'Hubert    Klein     Ikkink'
println ruler
println stringWithSpaces
println stringWithSpaces10

// Output:
// 0123456789012345678901234567890
// Hubert  Klein   Ikkink
// Hubert    Klein     Ikkink

assert 'Hubert\tKlein\tIkkink' == stringWithSpaces.unexpand()
assert 'Hubert\tKlein\tIkkink' == stringWithSpaces10.unexpand(10)

Groovy Goodness: Capitalize Strings

Groovy 1.7.3 adds the capitalize() method to the String class. This will capitalize the first letter of the String:

assert 'MrHaki' == 'mrHaki'.capitalize()
assert 'Groovy' == 'groovy'.capitalize()
assert 'Groovy is Gr8!' == 'groovy is Gr8!'.capitalize()

June 10, 2010

Groovy Goodness: Get Hints About Missing Methods or Properties

Groovy helps us if for example we make a small mistake in our code. We don't only get an error message, but also a hint about a possible solution. This works also for classes we create ourselves.

In the following example we use toUppercase() instead of toUpperCase(). Notice the suggestion we get from Groovy:

$ groovy -e "println 'mrhaki'.toUppercase()"
Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.String.toUppercase() is applicable for argument types: () values: []
Possible solutions: toUpperCase(), toUpperCase(java.util.Locale), toLowerCase(), toLowerCase(java.util.Locale)
 at script_from_command_line.run(script_from_command_line:1)

Suppose we define the following script:

class User {
    String name
    String giveName() { name }
}

def u = new User(name: 'mrhaki')
println u.givenName()

When we run this script we get the following output:

$ groovy UserScript.groovy 
Caught: groovy.lang.MissingMethodException: No signature of method: User.givenName() is applicable for argument types: () values: []
Possible solutions: giveName(), getName(), setName(java.lang.String)
 at UserScript.run(UserScript.groovy:7)

June 3, 2010

Groovy Goodness: Create Class Instance Dynamically

The Class method in Groovy has a newInstance() to dynamically create a new instance of a given class. We can use an Object array or Map as argument if we want to invoke the non-default constructor of the class.

class Blog {
    String name
    String subject
    
    Blog() {}
    
    Blog(String name, String subject) {
        this.name = name
        this.subject = subject
    }
}

def blog = Blog.newInstance()
assert !blog.name, 'Name has no value'
assert !blog.subject, 'Subject has no value'

def blog2 = Blog.newInstance(['mrhaki', 'Groovy'] as Object[])
assert 'mrhaki' == blog2.name
assert 'Groovy' == blog2.subject

def blog3 = Blog.newInstance([name:'mrhaki', subject: 'Groovy'])
assert 'mrhaki' == blog3.name
assert 'Groovy' == blog3.subject

May 26, 2010

Groovy Goodness: Use Collect with Initial Collection Value

The collect() method in Groovy can be used to iterate over collections and transform each element of the collection. The transformation is defined in as a closure and is passed to the collect() method. But we can also add an initial collection to which the transformed elements are added.

// Collect without 
// initial collection.
assert [0,2,4,6] == (0..3).collect { it * 2 }
assert ['Groovy', 'Grails'] == [lang: 'Groovy', framework: 'Grails'].collect { it.value }

// Collect with initial collection argument.
assert [0, 1, 2, 3] == [2, 3].collect([0, 1]) { it }
assert [0, 3, 6, 9] == [2, 3].collect([0, 3], { it * 3})
assert ['Gradle', 'groovy', 'grails'] == ['Groovy', 'Grails'].collect(['Gradle']) { it.toLowerCase() }
assert ['m','r','h','a','k','i'] == [4, -3, 7, 5].collect(['m', 'r']) { (it + 100) as char }

April 27, 2010

Groovy Goodness: Working on Files or Directories (or Both) with FileType

Working with files in Groovy is very easy. We have a lot of useful methods available in the File class. For example we can run a Closure for each file that can be found in a directory with the eachFile() method. Since Groovy 1.7.1 we can define if we only want to process the directories, files or both. To do this we must pass a FileType constant to the method. See the following example code:

import groovy.io.FileType

// First create sample dirs and files.
(1..3).each { 
 new File("dir$it").mkdir() 
}
(1..3).each { 
 def file = new File("file$it")
 file << "Sample content for ${file.absolutePath}"
}

def currentDir = new File('.')
def dirs = []
currentDir.eachFile FileType.DIRECTORIES, {
    dirs << it.name
}
assert 'dir1,dir2,dir3' == dirs.join(',')

def files = []
currentDir.eachFile(FileType.FILES) {
    files << it.name
}
assert 'file1,file2,file3' == files.join(',')

def found = []
currentDir.eachFileMatch(FileType.ANY, ~/.*2/) {
   found << it.name
}

assert 'dir2,file2' == found.join(',')