preface

Company projects also apply to the custom Gradle plugin, but I’m not involved in all the way, because is not I am responsible for another reason is that my Gradle related knowledge reserves is zero, just recently learned that, or you will forget in line with the good thought I was to learn the contents of all finishing processing, Gradle is an automatic project building tool based on The concepts of Apache Ant and Maven. It is implemented in Java. Therefore, we can consider Gradle as a lightweight Java application. Gradle uses Groovy, Kotlin, and other languages to write custom scripts. Instead of using XML configuration for Ant and Maven, Gradle greatly simplifies the configuration of project builds, making them more flexible and powerful. This article focuses on Groovy syntax. Here I recommend the Groovy tutorial, and the knowledge brain map for this article is below.

1. What is DSL

A DSL stands for domain-specific language, a computer language that focuses on an application Domain.

2. Strings

Strings in Groovy can be enclosed in single quotes (‘), double quotes (“), or triple quotes (” “). In addition, Groovy strings can span multiple lines enclosed in triple quotes, and expressions can be evaluated in double quotes using ${}, which can be omitted if the $sign is followed by only one variable.

String a = 'Hello World ! '
String b = "Hello Groovy ! ${a}"
String c = """ Hello Groovy !" ""
Copy the code

Execution Result:

Hello World !
Hello Groovy ! Hello World !
 
         Hello 
         Groovy !
Copy the code

3. Data types

Basic data types

Groovy provides a variety of built-in data types. Here is a list of the data types defined in Groovy, but you can also use def when defining variables. Type derivation helps you specify data types that are no longer displayed.

  • Byte – This is used to represent byte values. For example 2.

  • Short – This is used to indicate a short integer. For example, 10.

  • Int – This is used to represent integers. For example, 1234.

  • Long – This is used to indicate a long integer. For example, 10000090.

  • Float – This is used to represent 32-bit floating point numbers. For example, 12.34.

  • Double – This is used to represent 64-bit floating point numbers that are longer decimal representations that may sometimes be required. For example, 12.3456565.

  • Char – This defines a single character literal. Such as “A”.

  • Boolean – This represents a Boolean value, which can be true or false.

  • String – These are text represented as strings. For example, “Hello World”.

Data type range

type The scope of
byte 128 to 127
short 32768 to 32767
int From 2147483648 to 147483647
long 9223372036854775808 to + 9223372036854775807
float 1.40129846432481707E-45 to 3.40282346638528860 E + 38
double 4.94065645841246544E-324 D to 1.79769313486231570 E + 308D

Wrapper type

As in Java, there are wrapper types for primitive data types as well:

  • java.lang.Byte
  • java.lang.Short
  • java.lang.Integer
  • java.lang.Long
  • java.lang.Float
  • java.lang.Double

You can use BigInteger and BigDecimal to support high-precision calculations

BigDecimal d = 20.48
BigInteger e = 30
Copy the code

4, methods,

Method return value

The return value of a Groovy method can be expressed as a specific data type or def, and modifiers such as public, private, and protected can be added. By default, if no visibility modifier is provided, the method is public. Groovy treats the last line of code executed as the return value by default, so you can remove the return as well

//def as return value type (automatic type derivation)
def method(){
    return "Return value of Groovy method"
}

//Groovy defaults to treating the last line of code in execution as the return value
def method(def a){
   if(a == 1) {1
   }else{
       2}}Copy the code

Method to add default values

Groovy methods have default values for parameters, and methods are called with default values defined if they are not passed

// In Groovy methods you can add default values for parameters, and the default values defined when calling method methods are not passed are used
def method(def a = 1) {if(a == 1) {1
   }else{
       2
   }
Copy the code

I can omit the parentheses

Groovy methods can make code shorter by omitting the parentheses, such as the method method below

// Define the method
def method(int a){
    print(a)
}

//
e.method(1)

// omit the parentheses
e.method 1


Copy the code

If a method takes two parameters like method(int a,int b)

def method(int a,int b){
    print("$a $b")
}

e.method 1.3
Copy the code

5. Operator overloading

Groovy also has operator overloading, which is essentially calling a method in a class, in this case simply overloading the + operator

class Example {

    int number

    static void main(String[] args) {

        Example e1 = new Example(number: 1)

        Example e2 = new Example(number: 5)

        print(e1 + e2)

    }
    
    // The plus method corresponds to the + operator
    def plus(Example e){
        number+=e.number
    }

}
Copy the code

Operator overloading is very simple, which means overriding the methods that Groovy operators map to. The corresponding mapping methods can be seen in the following table

6, scope,

Groovy defines ranges. Since Range is a direct subclass of List, you can use the list-related API when manipulating Range

class Example {
    
    static void main(String[] args) {

       Range range01 = 1.10.// An example of a range

        def range02 = 1.. <10// An example of exclusive scope

        def range03 = 'a'.'z'// Ranges can also be composed of characters

        def range04 = 10.1.// Ranges can also be sorted in descending order

        def range05 = 'z'.'a'// Ranges can also be composed of characters in descending order

        range01.forEach{
            print(it)
        }
        range02.forEach{
            print(it)
        }
        range03.forEach{
            print(it)
        }
        range04.forEach{
            print(it)
        }
        range05.forEach{
            print(it)
        }
        
    }
}
Copy the code

7, the Map

Def Map = [‘ Shanghai ‘: ‘Shanghai ‘,’ Guangzhou ‘: ‘guangzhou’,]

def map = ['Shanghai': 'shanghai'.'guangzhou': 'guangzhou',]
// How to access map elements
defA = Mapdef b = map.get('guangzhou')
def c = map['Shanghai']
println("$a $b $c")
Copy the code

Execute export of Shanghai Guangzhou Shanghai

def map = ['Shanghai': 'shanghai'.'guangzhou': 'guangzhou',]
// Add elements
map['hefei'] = 'hefei'
// Delete elements
map.remove('Shanghai')
// Modify the elementMap. Guangzhou ='It's hot in Guangzhou'
// Iterate over the elements
map.each {
    print(Key = ${it. Key} Value = ${it. Value})}// Find elements
def  res = map.find {
    if (it.value == 'It's hot in Guangzhou') {
        return 'Guangdong needs air conditioning'
    }
    return 'no find city'
}
Copy the code

List and Array

List

Def list = [], or ArrayList

list = []

// Define a List
ArrayList<Integer> list = []
// Add elements
(1.10.).each {
    list.add(it)
}
/ / traverse the List
list.each {
    print(it)
}
// traversal with subscripts
list.eachWithIndex { int entry, int i ->
    print("Value ${entry} subscript ${I}")}// Access elements by subscript
def res = list[0]
print(res)
Copy the code

Array

Integer[] array = [1,3,9,1,4,6,0,3,6,7,4] or def array = [1,3,9,1,4,6,0,3,6,7,8] as Integer[]

def array = [1.3.9.1.4.6.0.3.6.7.8] as Integer[]
// Iterate over all elements
array.each {
    print(it)
}
// Get elements based on subscripts
def res = array[0]
// Find the first element that matches the condition based on the condition
def findRes = array.find {
    it == 3
}
// Find all eligible elements and return a collection
def findAllList = array.findAll{
    it == 3
}
// Return true as long as one condition is met
boolean isAny = array.any {
    it == 3
}
// Return true if all conditions are met
boolean  isEvery = array.every {
    (it % 3) = =0
}
Copy the code

9, closures

You can think of a Closure as a separate block of method code, and as an object called a Closure, you can think of a Closure object as an anonymous function that takes arguments, returns values and assigns them to variables.

Using closures

Using closures is actually pretty simple, so let’s implement a little function to implement a summation function, define a method that takes a value from 0 to n, take the value and throw it to the closure

def sum = 0
pickSum(100,{
    sum+=it
})

static def pickSum(n,block){
    for(int i=0; i<=n; i++){ block(i) } }Copy the code

So the pickSum here is a higher-order function, you can either treat the function as an input parameter or treat the function as a return value, and in the example code you’re going through 0 to n and you’re going to pass the value to a block, and that block can be thought of as a closure, If the closure is a function at the same time also can be written as the last parameter in the code below, when the closure is a method call last argument can attach a closure on the method call, if only to pass a parameter in the closure, it can use the variable to represent the parameters, but you can also use other name

pickSum(100){
    sum+=it
}
Copy the code

When you define a closure, you can either create a closure at the time of a method call or assign the closure to a variable for reuse, as in the above example, where we extract the block

def sum = 0
def block = {
    sum+=it
}
pickSum(100,block)
Copy the code

For single-parameter closures you can use IT to specify variables, but for multiple parameters you must use your own names

def block = {
    int a,int b -> a+b
}
 def sum(int a,int b){
    return  block(a,b)
}

print(example.sum(1.5))

// Output result 6

Copy the code

Dynamic closures

You can determine if a closure exists, if it does use the closure otherwise use the default implementation, in the following code if a closure is defined use the closure otherwise default implementation

void sum(block){
   if(block){
       block()
   }else{
       print("Use default value")
   }
}

 example.sum{
     print("Closure is used.")
 }
 
 example.sum()
 
Copy the code

Could be obtained by maximumNumberOfParameters method parameters passed in the closure, what else could be obtained through the parameterTypes closures in the data type of the refs

def res = example.sum(3){
    num,rate -> num * rate
}
def res2 = example.sum(3){
    it * 33
}
print(res2)


def sum(int num,Closure block){
    for (param in block.parameterTypes){
        println(param.name)
    }
   if(block.maximumNumberOfParameters == 2){
       block(num,4)}else{
       block(num)
   }
}

Copy the code

Commissioned by the closure

Inside a closure there are three properties that can only be used inside a closure: This, owner, and Delegate. You can call this, owner, and Delegate directly. This corresponds to the class that defines the closure and, if it’s an inner class, points to the inner class. If defined in a closure, corresponding to the closure, otherwise identical to this, delegate and owner, or custom delegate pointing, the point of setting the delegate is to associate the closure with a specific object

class Example {

    String name

    int age

    void eat(String food){
        print("like eat ${food}")}@Override
    String toString() {
        return "name = $name age = $age"
    }

    static void main(String[] args) {
        // Define a closure that modifies the properties of the object in the closure. You can also call object methods in the closure and access the properties and methods of the propped object
        def block = {
            name = 'tengfei'
            age = 18
            eat('KFC')
        }

        Example example = new Example(name: 'feifei'.age: 28)

        println(example.toString())
        // Associate closures with concrete objects via a delegate
        block.delegate = example
        block.call()

        println(example.toString())
        
    }

}
Copy the code