Gradle 之Groovy基本语法(一)

  • Gradle 之Groovy基本语法(一)
  • Gradle 之Groovy文件操作(二)
  • Gradle 之详解Project(三)
  • Gradle 之详解Task(四)
  • Gradle 之初识插件(五)
  • Gradle 之常用配置(六)
  • Gradle 之扩展Extension类 (七)

一、前言

在做Android开发的时候,IDE是Android Studio,而项目构建是Gradle。Gradle负责将我们写的代码打包成为最终可以执行的东西。在以前的项目构建都是用Ant和Maven等。之前的如Ant、Maven都采用XML配置的方式来构建打包脚本的,Gradle比较强的原因就在于Gradle中使用了Groovy语言,可以编写复杂的功能,这是使用XML很难做到的。

借用百度百科对Groovy的介绍:Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy 可以使用其他 Java 语言编写的库。

从中可以了解,Groovy和Kotlin一样,他们都是基于JVM的语言,这样java和groovy就可以无缝切换了。再者Groovy在结合了其他优秀的语言的特性。第三Groovy是个DSL领域特定语言,不求博只求专,是特长就是写脚本。

使用Groovy前需要有些步骤:

  • 下载Groovy sdk并配置环境变量 可见 https://www.jianshu.com/p/777cc61a6202
  • 下载一个编写环境软件,我这用的是IDEA
  • 新建一个Groovy项目即可

二、Groovy基本对象

1、基本类型

int i = 10
long l = 4l
float f = 4.4f
double d = 3.3d
short s = 2
char c = 'h'
byte b = 0b010101
boolean bool = true

println("i = "+i+"   类型:"+i.getClass())
println("l = "+l+"   类型:"+l.getClass())
println("f = "+f+"   类型:"+f.getClass())
println("d = "+d+"   类型:"+d.getClass())
println("s = "+s+"   类型:"+s.getClass())
println("b = "+b+"   类型:"+b.getClass())
println("c = "+c+"   类型:"+c.getClass())
println("bool = "+bool+"   类型:"+bool.getClass())
Gradle 之Groovy基本语法(一)_第1张图片
结果

groovy的基本类型同java一样,简单就稍微演示了。同java一样虽然是int型的,但通过getClass判断却是Integer类。

  • 二进制 0b前缀
  • 八进制 0前缀
  • 十六进制 0X前缀

2、字符串

Groovy沿用了java中的String对象和自己的GString对象。对于String和java中的一致。

常用的定义方式:
def str1 = '我是\'字符串'
def str2 = "我是'字符串 ${str1}"
def str3 = '''
我是'字符串'''

println("str1 = " + str1+"   类型:"+str1.getClass())
println("str2 = " + str2+"   类型:"+str2.class)
println("str3 = " + str3+"   类型:"+str3.getClass())
  • 单引号 和 java中的双引号一致。
  • 双引号 可以直接的在中间写特殊的字符而不用加入反斜杠,使用双引号更加的适用于业务
  • 三个单引号 这是对双引号的加强版,三个单引号可以使换行处理,属于有格式的

用def定义,可以自动推导当前的类型。对于Str2,它属于GString类了。可以在${}放入一个表达式,结果值会作为字符串的一部分内容。

String不能转化成GString,而GString可以转化成String。

对于String中的方法分为三类:

  • java.lang.String
  • DefaultGroovyMethods
  • StringGroovyMethods

如:
str.reverse()反转
str.capitalize() 首字母大写
str[0] 获取一个字符
str[0..4] 截取第0个到第四个之间的字符串
str.eachLine {line->println(line)} 闭包获取每一行字符串

3、闭包

按照我的理解闭包就是一个代码块,这个代码块有点特殊,他可以像方法一样接受参数、执行并返回结果。

// 定义一个带有闭包参数的方法
String echo(Closure closure, int num1, int num2) {
    closure.call(num1, num2)
}

// 调用闭包方法
String s1 = echo({ num1, num2 ->
    "${num1}+${num2} = ${(num1 + num2)}"
}, 1, 2)

println(s1)


String s2 = echo({ num1, num2 ->
    "${num1}-${num2} = ${(num1 - num2)}"
}, 1, 2)

println(s2)

// 结果:
// 1+2 = 3
// 1-2 = -1

上面的echo方法就是接收一个闭包参数,该闭包是接收两个参数,根据策略计算并返回结果。闭包的定义是采用Closure,可以用closure.call(num1, num2)执行闭包。执行echo方法时,一个传入的是计算加法的闭包,另一个是计算减法的闭包。这个就像策略一样,你负责传入策略我给你相应的结果。

调用方式:
  • closure.call(num1, num2) : 采用call方法
  • closure(num1, num2) : 以方法的形式
闭包的参数:
  • 显示参数
    闭包中显示的指明具体的参数。
  • 隐士参数
    groovy中使用隐士it代表传入的参数,有且只能由0个或一个参数才行。
def colusre = {
    println("my name is ${it}")
}

colusre()
colusre("phj")

// 结果:
// my name is null
// my name is phj

对于第一个不传入参数的就是null,而且在闭包的声明中也没有指明是否有参数,而是使用了it代替。

闭包的返回值:

闭包都是有返回值的,在没有显示return返回的时候,最后一行就是返回的内容。如果最后一行是void形式,那么返回值就是null。

闭包使用:
int cal(int number) {
    int  result = 0
    number.times({num->result+=num})
    result
}

println(cal(10))

利用闭包实现从1加到9,结果等于45。

看下times源码:

    public static void times(Number self, @ClosureParams(value = SimpleType.class,options = {"int"}) Closure closure) {
        int i = 0;

        for(int size = self.intValue(); i < size; ++i) {
            closure.call(i);
            if (closure.getDirective() == 1) {
                break;
            }
        }

    }

就是循环的调用闭包,在执行闭包的时候将之前的数据累加起来。

常见字符串闭包函数
  • str.find(Closure closure) 查找满足条件的第一个数
  • str.findAll(Closure closure) 查找所有满足条件的数
  • str.any(Closure closure) 判断是不是有一个数满足闭包的要求的
  • str.collect(Closure closure) 遍历返回转换后的字符List
闭包的变量
  • this
  • owner
  • delegate
def colusre = {
    println(this)   : 代表闭包定义处的类
    println(owner)   : 代表闭包定义处的类或者对象
    println(delegate)  : 代表任意对象,默认是和owner一致
}

执行该闭包的结果是:com.phj.groovy为包名,T为类名,后面是T的对象。从结果来看这三个的打印都是一样,都代表了同一个对象。

com.phj.groovy.T@35e2d654
com.phj.groovy.T@35e2d654
com.phj.groovy.T@35e2d654

再如:

def colusre = {
    def interColusre = {
        println(this)
        println(owner)
        println(delegate)
    }
    interColusre()
    println(this)
    println(owner)
    println(delegate)
}

它的执行结果就是:

com.phj.groovy.T@55183b20
com.phj.groovy.T$_run_closure4@7d8995e
com.phj.groovy.T$_run_closure4@7d8995e
com.phj.groovy.T@55183b20
com.phj.groovy.T@55183b20
com.phj.groovy.T@55183b20

因为interColusre 是定义在闭包里面,所以这里面的值就不是和this一致了,而是指代着外边运行的闭包对象。而delegate默认是和owner一样。

再者看下delegate:

def colusre = {
    def interColusre = {
        println(this)
        println(owner)
        delegate = this
        println(delegate)
    }
    interColusre()
}

在内部的闭包interColusre将delegate指明为this。

结果:这样就修改了delegate对象了

com.phj.groovy.T@55183b20
com.phj.groovy.T$_run_closure4@7d8995e
com.phj.groovy.T@55183b20
闭包的委托策略:

即通过delegate来指向新的数据。

class Student {
    def name

    def pretty = {"my name is ${name}"}

    String toString() {
        pretty.call()
    }
}

class Teacher {
    def name
}

def student = new Student(name:"student")
def teacher = new Teacher(name:"teacher")

println(student.toString())
student.pretty.delegate = teacher
// 修改委托策略
student.pretty.resolveStrategy =  Closure.DELEGATE_FIRST
println(student.toString())

结果:

my name is student
my name is teacher

定义两个类,两个类都有同样的属性,现在通过更改委托和委托策略将student中打印的name指向teacher中的name。

三、基本数据结构

1、List列表

定义方式:

  • def list = new ArrayList() : java的定义方式
  • def list = [1,2,3,] : groovy的定义方式

List中有很多子List,如ArrayList和LinkedList等。

List操作:

  • add : list.add(1)
  • remove :list.remove(1)
  • 排序 :Collections.sort(list)
  • 遍历 :list.forEach()
  • 查找 : list.find()
2、Map字典

定义方式:

  • def map = new HashMap() : java中定义的方法
  • def map = [1:"first",2:"second"] : groovy中定义方式

Map操作:

  • 增 :map[3] = 'third' 或者 map.put(3,'third')
  • 删 :map.remove()
  • 查 :map[1] 或者map.get()
  • 排序 :map.sort()
  • 遍历 :map.forEach()或者 map.each() 或者 map.eachWithIndex()

需要注意的是:Map中的value的类型不一定是固定的,可以是任意类型的。

3、Range范围

Range是List的一个子类
定义方式:

  • def range = 1..10 代表1到10

操作:

  • range.from : 开始值
  • range.to : 结束值
  • 查 :range[0]或者range.get()
  • 遍历 :range.each()

四、面向对象

类定义:

class Student {
    String name
}

def student = new Student(name:"name")
  • 类中的方法和参数默认是public的
  • 不用构造方法也可以调用有参构造方法
  • 类中默认设置了getXXX方法获取属性

接口定义:
接口中不能有非public的方法

interface Action {
    void eat()
}

trait定义:
trait有点像抽象类,里面可以有无结构体的抽象方法,也可以实现默认的方法。但得通过implements来实现。

trait DefaultAction {
    abstract void eat()
    
    void play() {
        
    }
}
groovy运行机制
Gradle 之Groovy基本语法(一)_第2张图片
Runtime机制

在java中调用方法正常的逻辑就是直接调用某一个方法,如果没有该方法,编译器就会报错,但是在groovy中却不一样,即使没有该方法也不一定会抛出异常。上图就是groovy中的运行机制。

例一:invokeMethod
class Student {
    String name

    @Override
    Object invokeMethod(String s, Object o) {
        println("s(${o})")
        return null
    }
}

重写了Student中的invokeMethod方法,s代表方法名,o代表参数

调用student中没有的方法

def student = new Student()
student.cry()

// 结果:
// s([])

结果没有抛出异常,而是走了invokeMethod方法。

例二:methodMissing
class Student {
    String name

    @Override
    Object invokeMethod(String s, Object o) {
        println("s(${o})")
        return null
    }

    def methodMissing(String name, Object args) {
        println("the method ${name} is missing")
    }
}

在加入methodMissing方法后,就不会走invokeMethod方法,而是走了methodMissing方法。

例三:metaClass

通过metaClass可以动态的为一个类增加属性和方法
如:

  • Student.metaClass.age = 24 : 注入属性
  • Student.metaClass.cry = {"i am cry"} : 注入方法

你可能感兴趣的:(Gradle 之Groovy基本语法(一))