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 mandatory. Both single quotes and double quotes define a string constant. The difference is that single quotes are purely 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{
// Use the def keyword to define variables,
def str1 = "Double quotes"
def str2 = 'Single quotes'
println "String defined with double quotes:"+str1
println "String defined with double quotes:"+str1.class
println "String defined with single quotes:"+str2
// Variable dynamic change
str1 = true;
println "String defined with double quotes:"+str1.class
// Use 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"
// String 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
String defined with double quotes:class java.lang.String
String defined with single quotes:Single quotes
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 element variable, do not write it incorrectly
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 collections in Groovy.
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 section of code enclosed in curly braces, and in Groovy, code blocks can be passed as parameters. You can refer to the previous section on 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
}
)
// Groovy specifies that if the last parameter of the method is a closure, it can be placed outside the method
list.each(){
// println it
}
// Shortened form
list.each{
println it
}
}
// Method definition
def methodA(int a, int b){
println a + b
// In Groovy, the return statement is not mandatory; it defaults to the result of the last line of code as the return value
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 those in Java. You can directly use the javaBean.property method to get and modify the property values of a JavaBean without using 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 corresponding to the property 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:
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 block of code 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, 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 closure parameter i, which defaults to the it variable if there is one parameter
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. When the closure has multiple parameters, the parameters need to be defined. For specific details, 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 is a definition of a closure and a method, with prints to illustrate some differences among these three properties:
// 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 processed using thisObject first
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 called 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, the delegate is generally specified as the current it, allowing us to operate on it through the object specified by the delegate. Below is the test code that specifies the closure's delegate and sets the delegation priority, allowing the specific object of the delegate to execute its methods:
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 currently 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 needed, we can look at advanced usage of Groovy later.