Gradle 之Groovy基本语法(一)

一、前言

在做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基本对象

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())
结果

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运行机制
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"} : 注入方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容