Previous learned the basics of Gradle, which is based on Groovy. Today, let's learn some basic knowledge of Groovy. Groovy is a dynamic language based on the JVM virtual machine, with syntax similar to Java. Groovy is fully compatible with Java, and every Gradle file is a Groovy script file. Gradle files are based on Groovy syntax, and since Groovy is compatible with Java, Java code can be written in Gradle files. On this basis, many new features have been added, such as support for closures, DSL, etc. It can be said that Groovy is a very flexible dynamic scripting language. Let's learn some basic knowledge of Groovy in the context of Gradle.
- Strings
- Collections
- Methods
- JavaBeans
- About Closures
Strings#
One feature of Groovy is that semicolons are not required. Both single quotes and double quotes define a string constant. The difference is that single quotes are pure string constants and do not evaluate expressions within the string, while string constants defined with double quotes can use valid expressions for related calculations. The test code is as follows:
task stringTest{
// Define variables using the def keyword,
def str1 = "double quotes"
def str2 = 'single quotes'
println "String defined with double quotes:"+str1
println "Type of string defined with double quotes:"+str1.class
println "String defined with single quotes:"+str2
// Variable dynamically changes
str1 = true;
println "Type of string defined with double quotes:"+str1.class
// Using the $ operator
println "String defined with double quotes:${str1}"
// When there is only one variable, brackets can be omitted
println "String defined with double quotes:$str1"
// Strings defined with single quotes cannot use expressions for calculations
println 'String defined with single quotes:$str2'
}
Below is the execution result for reference:
PS E:\Gradle\study\Groovy> gradle stringTest
> Configure project :
String defined with double quotes:double quotes
Type of string defined with double quotes:class java.lang.String
String defined with single quotes:single quotes
Type of string defined with double quotes:class java.lang.Boolean
String defined with double quotes:true
String defined with double quotes:true
String defined with single quotes:$str2
BUILD SUCCESSFUL in 1s
Collections#
Groovy also has the concept of collections, mainly looking at commonly used List and Map. Below, we will introduce common operations for List and Map.
So how do you define a List in Groovy? The definition of List in Groovy is similar to arrays in Java. The specific operations are as follows:
task list{
// Define List
def list = [1,2,3,4,5,6];
def weekList = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'];
println "Type of list:"+list.class
println "Type of weekList:"+weekList.class
// Access elements in the collection
println 'First element:'+list[0]// Access the first element
println 'Second element:'+list[1]// Access the second element, and so on
println 'Last element:'+list[-1]// Access the last element
println 'Second to last element:'+list[-2]// Access the second to last element, and so on
println 'Elements in a certain range:'+list[2..4]// Access elements in a certain range, and so on
// Use each to iterate over elements in the collection
weekList.each{
// Use it as the iteration variable, do not get it wrong
println it
}
}
Below is the execution result of the above code for reference:
PS E:\Gradle\study\Groovy\ListMap> gradle list
> Configure project :
Type of list:class java.util.ArrayList
Type of weekList:class java.util.ArrayList
First element:1
Second element:2
Last element:6
Second to last element:5
Elements in a certain range:[3, 4, 5]
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
BUILD SUCCESSFUL in 2s
So how do you define a Map in Groovy? A Map in Groovy is of course a key-value pair. The specific definition and operations are as follows:
task map{
// Define Map
def map = ['name':'Groovy', 'age':10];
println "Type of map:"+map.getClass().name;
// Access elements in the Map
println map.name;
println map['name'];
// Iterate over elements in the Map
map.each{
println "Key:${it.key}, value:${it.value}"
}
}
Below is the execution result of the above code for reference:
PS E:\Gradle\study\Groovy\ListMap> gradle map
> Configure project :
Type of map:java.util.LinkedHashMap
Groovy
Groovy
Key:name,value:Groovy
Key:age,value:10
BUILD SUCCESSFUL in 2s
That's all for understanding Groovy's collections.
Methods#
Methods in Groovy are similar to those in Java, but the syntax is more flexible. In Groovy, return is not mandatory. When return is not written, Groovy will treat the last line of code as the return value of the method. A code block refers to a segment of code enclosed in curly braces, and in Groovy, code blocks can be passed as parameters. You can refer to the earlier part about iterating over collections. The reference code is as follows:
task method{
// Method call
methodA(1, 2)
methodA 1, 2
// Get the result returned by the method
def a = methodA 10, 20
println 'Get the result returned by the method:'+a
// Code block passed as a parameter
def list = [1,2,3,4,5];
list.each(
// Closure parameter
{
// println it
}
)
// In Groovy, if the last parameter of a method is a closure, it can be placed outside the method
list.each(){
// println it
}
// Shortened syntax
list.each{
println it
}
}
// Method definition
def methodA(int a, int b){
println a + b
// In Groovy, the return statement is not mandatory; the result of the last line of code is returned by default
a + b
}
Below is the execution result of the above code for reference:
PS E:\Gradle\study\Groovy\Method> gradle method
> Configure project :
3
3
30
Get the result returned by the method:30
1
2
3
4
5
BUILD SUCCESSFUL in 2s
JavaBean#
JavaBeans in Groovy are more flexible compared to Java. You can directly access and modify JavaBean properties using the javaBean.property syntax without needing to use the corresponding Getter and Setter methods. Let's look at the code directly:
task javaBean{
// Define JavaBean in Groovy
Student student = new Student()
student.name = "Groovy"
student.age = 10
student.setName("Gradle")
println "Name is:"+student.name
// Cannot call Getter method to get value
// println "Name is:"+student.getName
println "Age is:${student.age}"
println "Score is:"+student.score
}
class Student{
private String name
private int age
// The defined Getter method can be called directly
public String getScore(){
100
}
// Getter and Setter methods for properties
public String setName(String name){
this.name = name
}
public void getName(){
name
}
}
Below is the execution result of the above code for reference:
PS E:\Gradle\study\Groovy\JavaBean> gradle javaBean
> Configure project :
Name is:Gradle
Age is:10
Score is:100
BUILD SUCCESSFUL in 2s
Closures#
Closures are a feature found in most scripting languages, such as JavaScript and Groovy. A closure is a code block surrounded by curly braces. Let's learn about closures in Groovy, which mainly consists of two parts: closures and closure parameter passing, and closure delegation.
Closures and Parameter Passing#
Let's see how to define a closure and pass related parameters, with the code as follows:
task closure{
// Custom closure execution
mEach{
println it
}
// Pass parameters to the closure
mEachWithParams{m,n -> // m,n -> separates closure parameters from the body
println "${m} is ${n}"
}
}
// 1. Define a method, the parameter closure is used to receive the closure
// 2. The execution of the closure is the execution of the code inside the curly braces
// 3. The parameters received by the closure are the i in the closure parameter closure; if there is one parameter, it defaults to the it variable
def mEach(closure){
for(int i in 1..5){
closure(i)
}
}
// Pass parameters to the closure
def mEachWithParams(closure){
def map = ["name":"Groovy","age":10]
map.each{
closure(it.key, it.value)
}
}
The above code defines a closure and how to pass parameters to the closure. When the closure has only one parameter, it defaults to it; otherwise, when the closure has multiple parameters, they need to be defined explicitly. For specific details, please refer to the above code. Below is the execution result:
PS E:\Gradle\study\Groovy\Closure> gradle delegate
> Configure project :
1
2
3
4
5
name is Groovy
age is 10
BUILD SUCCESSFUL in 2s
Closure Delegation#
The power of Groovy closures lies in their support for closure method delegation. Groovy closures have three properties: thisObject, owner, and delegate. When a method defined within a closure is called, these three properties determine which object executes the method. By default, owner and delegate are equal, but delegate can be modified. Many features of closures in Gradle are implemented by modifying the delegate. Below, we define a closure and a method to illustrate some differences between these three properties through printing:
// Closure delegation
task delegate{
new Delegate().test{
// Three properties of Groovy closures: thisObject, owner, delegate
println "thisObject:${thisObject.getClass()}"
println "owner:${owner.getClass()}"
println "delegate:${delegate.getClass()}"
// Default it in the closure
println "Default it in the closure:"+it.getClass()
// The defined method is prioritized to use thisObject
method()
// Method in the closure
it.method()
}
}
def method(){
println "method in root:${this.getClass()}"
}
class Delegate{
def method(){
println "method in Delegate:${this.getClass()}"
}
// Closure
def test(Closure<Delegate> closure){
closure(this);
}
}
Below is the execution result of the above code for reference:
PS E:\Gradle\study\Groovy\Closure> gradle delegate
> Configure project :
thisObject:class build_3ajca04o1rprxygcsq0ajvt7i
owner:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
delegate:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
Default it in the closure:class Delegate
method in root:class build_3ajca04o1rprxygcsq0ajvt7i
method in Delegate:class Delegate
BUILD SUCCESSFUL in 2s
When calling the method method() within the closure, it is found that thisObject calls the method(), not owner or delegate, indicating that the closure prioritizes using thisObject to handle method execution. It can also be seen that owner and delegate are consistent, but owner has a higher priority than delegate. Therefore, the order of method handling in closures is: thisObject > owner > delegate.
In Gradle, delegate is generally specified as the current it, allowing us to operate on it through the object specified by delegate. Below, we specify the delegate of the closure and set the delegation priority, allowing the specific object of the delegate to execute its methods. The test code is as follows:
task student{
configStudent{
println "Current it:${it}"
name = "Groovy"
age = 10
getInfo()
}
}
class Student{
String name
int age
def getInfo(){
println "name is ${name}, age is ${age}"
}
}
def configStudent(Closure<Student> closure){
Student student = new Student()
// Set the delegate object to the current created Student instance
closure.delegate = student
// Set the delegation mode priority; if not set, the method handler in the closure is thisObject
closure.setResolveStrategy(Closure.DELEGATE_FIRST)
// Set the it variable
closure(student)
}
Below is the execution result of the above code for reference:
PS E:\Gradle\study\Groovy\Closure> gradle student
> Configure project :
Current it:Student@18f6d755
name is Groovy, age is 10
BUILD SUCCESSFUL in 2s
Summary#
The purpose of learning Groovy is to deepen the understanding of the Gradle build tool. The above has provided a preliminary understanding of Groovy from five aspects. If there is a need in the future, we can look into the advanced usage of Groovy.