gradle7 从上手到实践之 groovy 基础语法

如何创建一个 groovy 项目?
使用 idea 按照下图的选项创建一个新项目:


创建 groovy 项目

1 变量

//无基本类型,均为对象类型
//不用写分号
int x = 10
println x.class

//可以无需指定类型
def y = 2
def z = 3.14

变量部分核心要点:

  • 没有基本变量,都是包装类
  • 语句结尾没有分号
  • 定义变量可以不指定类型,由编译器自动推断类型

2 字符串

  • 单引号与 java 中的字符串类似
  • 双引号字符串可以使用 ${} 引用表达式的值
  • 三引号字符串自带格式
//单引号
def name = 'a single string'
//双引号,可扩展字符串
def name2 = "simple string"
def sayName2 = "Hello ${name2}" 
def sum = "The sum of 2 and 3 equals ${2 + 3}"
//三引号,格式不变
def name3 = '''\
line one
line two
line three
'''

/字符 串的填充
def str = "groovy Hello"
println str.center(8, 'a') //agroovya

//padLeft padRight
println str.padLeft(8, 'a') //aagroovy

//字符串的比较
def str2 = 'Hello'
println str.compareTo(str2)
println str > str2

//字符获取
println str.charAt(0)
println str[0]
println str[0..1]

//减法
println str.minus(str2)
println str - str2

//字符串倒叙
println str.reverse()
//字符串首字母大写
println str.capitalize()
//字符串是否能装换为数字
println str.isNumber()

3 流程控制

//switch
def x = 1.23
def result

switch (x) {
    case 'foo'
        result = 'foo'
        break
    case [4,5,6,'inlist'] //列表
        result = 'list'
        break
    case 12..30:        //范围
        result = 'range' 
        break
    case BigDecimal:    //类型
        result = 'bigdecimal'
        break
    default: 
        result = 'default'
        break
}

println result

//for
def sum = 0
for(i in 0..9) {
    sum += i
}
println sum

for(i in [1,2,3,4,5,6,7,8,9]) {
    sum  += i
}

for(i in ['lili':1,'lucky':2,'xm':3]) {
    sum += i.value
}

4 闭包

闭包就是一段可以执行的代码,可以有输入参数,有返回值

//无参数情况
def clouser = { println 'Hello groovy'}
clouser.call()
clouser()

//有参数的情况
def clouser2 = { String name -> "Hello ${name}" }
clouser2.call("groovy")
clouser2("groovy")

//多个参数
def clouser3 = { String name, int age -> "Hello ${name}, my age is ${age}" }
clouser3.call("groovy",4)
clouser3("groovy",4)

//it的作用
def clouser4 = {
    println "Hello ${it}"
}
clouser4("groovy")

def clouser5 = { String name ->
    return "Hello ${name}"
}
println(clouser5('Groovy'))

//闭包的返回值
def clouser5 = { String name ->
    "Hello ${name}" //最后一行就是返回值
}
println(clouser5('Groovy'))

//闭包组合 rightshift: >>    leftshift: <<
//文档中示例
def twice = { a -> a * 2 }
def thrice = { a -> a * 3 }
def times6 = twice >> thrice
// equivalent: times6 = { a -> thrice(twice(a)) }
assert times6(3) == 18

def twice = { a -> a * 2 }
def thrice = { a -> a * 3 }
def times6 = thrice << twice
// equivalent: times6 = { a -> thrice(twice(a)) }
assert times6(3) == 18

//一个更为清晰的实例
def add = { a -> a + 5 }
def mult = { a -> a * 4 }
def rightShift = add >> mult//先+再*
def leftShift = add << mult//先*再+
assert rightShift(3) == 32
assert leftShift(3) == 17

5 闭包与字符串

方法的最后一个参数是闭包,可以不写在括号中

String str = 'the 2 and 3 is 5'

str.each { String temp -> 
    println temp
}

str.find { String s -> 
    s.isNumber()
}

def list = str.findall { String s -> 
    s.isNumbner 
}
println list.toListString()

def result = str.any { String s -> 
    s.isNumber
}
println result //返回 true

def result = str.every { String s -> 
    s.isNumber()
}
println result //返回 false

def list2 = str.collect { it.toUpperCase()}
println list2.toListString()

6 闭包进阶

在闭包内部可以访问闭包的参数,也可以访问很多其他的变量和函数,比如 gradle 脚本中的依赖:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

dependencyResolutionManagement 是一个方法,其参数是一个闭包。闭包内部调用了很多方法,那这些方法是哪里来的呢?
要知道这些方法从哪里来?我们需要理解 this, owner, delegate:

  • this: refers to the instance of the class that the closure was defined in.
  • owner: is the same as this, unless the closure was defined inside another closure in which case the owner refers to the outer closure.
  • delegate: is the same as owner. But, it is the only one that can be programmatically changed, and it is the one that makes Groovy closures really powerful.

当在闭包内访问一个变量时,闭包查找这个变量的顺序是:

  • 闭包内部
  • this
  • owner
  • delegate

可以使用 resolvedStrategy 方法改变这个顺序,这个方法接受的参数有(了解即可,一般都不用):

  • Closure.OWNER_FIRST
  • Closure.DELEGATE_FIRST
  • Closure.OWNER_ONLY
  • Closure.DELEGATE_ONLY

为加深理解,下面来看几个示例:

//理解三个引用的指向
class MyClass {
  def outerClosure = {
    println this.class.name    // outputs MyClass
    println owner.class.name    // outputs MyClass
    println delegate.class.name  //outputs MyClass
    def nestedClosure = {
      println this.class.name    // outputs MyClass
      println owner.class.name    // outputs MyClass$_closure1
      println delegate.class.name  // outputs MyClass$_closure1
    }
    nestedClosure()
  }
}
def closure = new MyClass().outerClosure
closure()



//理解变量的访问顺序
class MyClass {
  String myString = "myString1"
  def outerClosure = {
    println myString;     // outputs myString1
    def nestedClosure = {
       println myString;  // outputs myString1
    }
    nestedClosure()
  }
}
MyClass myClass = new MyClass()
def closure = new MyClass().outerClosure
closure()
println myClass.myString




//理解变量的访问顺序
class MyClass {
  def outerClosure = {
    def myString = "outerClosure";     
    def nestedClosure = {
       println myString;  // outputs outerClosure
    }
    nestedClosure()
  }
}
MyClass myClass = new MyClass()
def closure = new MyClass().outerClosure
closure()




//理解 delegate 的作用
class MyOtherClass {
  String myString = "I am over in here in myOtherClass"
}
class MyClass {
  def closure = {
    println myString
  }
}
MyClass myClass = new MyClass()
def closure = new MyClass().closure
closure.delegate = new MyOtherClass()
closure()   // outputs: "I am over in here in myOtherClass"



//理解 delegate 的作用
class MyOtherClass {
  String myString = "I am over in here in myOtherClass"
}
class MyOtherClass2 {
  String myString = "I am over in here in myOtherClass2"
}
class MyClass {
  def closure = {
    println myString
  }
}
MyClass myClass = new MyClass()
def closure = new MyClass().closure
closure.delegate = new MyOtherClass()  
closure()     // outputs: I am over in here in myOtherClass
closure = new MyClass().closure
closure.delegate = new MyOtherClass2() 
closure()     // outputs: I am over in here in myOtherClass2

有了上面的基础,我们把省略的源码补充完整:

dependencyResolutionManagement { DependencyResolutionManagement management ->
    management.repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    management.repositories { RepositoryHandler handler ->
        handler.google()
        handler.mavenCentral()
    }
}

7 数据结构

List:

def list = [1,2,3,4,5]              //ArrayList
def array = [1,2,3,4,5] as int[]    //定义一个数组
int[] array2 = [1,2,3,4,5]

def list2 = new ArrayList<Integer>()
list.add(1)
list.add(2)
list.add(3)

//排序
def sortList = [6,-3,9,2,-7,1,5]   
//方法一,来至 java
Comparator mc = { a, b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 }
Collections.sort(sortList, mc)
println sortList
//方法二,来至 Groovy
sortList.sort()
println sortList

sortList.sort { a, b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1  }

def sortStringList = ['abc', 'z', 'Hello', 'groovy', 'java']
sortStringList.sort { return it.size()} //根据长度排序

//查找
def findList = [-3, 9, 6, 2, 4, 5, 7]
int result = findList.find {return it % 2 == 0}
println result

def result = findList.findAll {return it % 2 != 0}

def result = findList.any {  //返回 true
  return it % 2 != 0
}

def result = findList.every { return it % 2 == 0}
println result

findList.min()  //查找最小值
findList.max()  //查找最大值

findList.min {return Math.abs(it)} //查找绝对值最小

findList.count {
  return it % 2 == 0
}

Map:

//Map
//定义和初始化
def map = new HashMap()
def colors = [red:'ff0000', green:'00ff00', blue:'0000ff']
//成员访问与赋值
colors['red']
colors.red 
colors.yellow = 'ffff00'
println colors.toMapString()
colors.complex = [a : 1, b : 2] 

def students = [
        1: [number: '0001', name: 'Bob',
            score : 55, sex: 'male'],
        2: [number: '0002', name: 'Johnny',
            score : 62, sex: 'female'],
        3: [number: '0003', name: 'Claire',
            score : 73, sex: 'female'],
        4: [number: '0004', name: 'Amy',
            score : 66, sex: 'male']
]

//遍历
stdudents.each { def student ->
    println "the key is ${student.key}, " +
            "the value is ${student.value}"
}

stdudents.eachWithIndex { def student, int index ->
    println "the index is ${index} " +
            "the key is ${student.key}, " +
            "the value is ${student.value}"
}

students.each { key, value ->
     println "the key is ${key}, " +
            "the value is ${value}"
}

students.eachWithIndex { key, value, index ->
      println "the index is ${index} " +
            "the key is ${student.key}, " +
            "the value is ${student.value}" 
}

//查找
def entry = students.find { def student ->
    return student.value.score >= 60
}
println entry

def entrys = students.findAll { def student ->
    return student.value.score >= 60
}

def count = students.count {def student ->
    return student.value.score >= 60
}

def names = students.count {def student ->
    return student.value.score >= 60
}.collect {
  return it.value.name
}


def group = students.groupBy { def student -> 
    return student.value.score >= 60 ? '及格' : '不及格'
}
println group.toMapString()

def sort = student.sort{ def student1, def student2 -> 
    Number score1 = student1.value.score
    Number score2 = student2.value.score
    return score1 == score2 ? 0 : score1 < score2 ? -1 : 1 
}
println sort.toMapString()

Range:

def range = 1..10
println range[0]
println range.contains(10)
println range.from
println range.to

range.each {
  println it
}

for(i in range) {
  println i
}

def getGrade(Number number) {
  def result
  switch(number) {
    case 0..<60:
        result = '不及格'
        break
    case 60..<70
        result = '及格'
        break
    case 70..<80
        result = '良好'
        break
    case 80..100
        result = '优秀'
        break
  }
}

8 文件操作

def file = new File('../../GroovySpecification.iml')

file.eachLine { line ->
   println line
}

def text = file.getText()
println text

def result = file.readLines()

//读取文件部分内容
def reader = file.withReader { reader ->
    char[] buffer = new char[100]
    reader.read(buffer)
    return buffer
}
println reader

def result = copy('../../GroovySpecification.iml'
       , '../../GroovySpecification2.iml')
println result

def copy(String sourcePath, String destationPath) {
    try {
        //首先创建目标文件
        def desFile = new File(destationPath)
        if (!desFile.exists()) {
            desFile.createNewFile()
        }

        //开始copy
        new File(sourcePath).withReader { reader ->
            def lines = reader.readLines()
            desFile.withWriter { writer ->
                lines.each { line ->
                    writer.append(line + "\r\n")
                }
            }
        }
        return true
    } catch (Exception e) {
        e.printStackTrace()
    }
    return false
}

def person = new Person(name: 'Qndroid', age: 26)
saveObject(person, '../../person.bin')

def result = (Person) readObject('../../person.bin')
println "the name is ${result.name} and the age is ${result.age}"

def saveObject(Object object, String path) {
    try {
        //首先创建目标文件
        def desFile = new File(path)
        if (!desFile.exists()) {
            desFile.createNewFile()
        }
        desFile.withObjectOutputStream { out ->
            out.writeObject(object)
        }
        return true
    } catch (Exception e) {
    }
    return false
}

def readObject(String path) {
    def obj = null
    try {
        def file = new File(path)
        if (file == null || !file.exists()) return null
        //从文件中读取对象
        file.withObjectInputStream { input ->
            obj = input.readObject()
        }
    } catch (Exception e) {

    }
    return obj
}

9 json 和 xml 操作

json:


import groovy.json.JsonOutput
import groovy.json.JsonSlurper

class Person {
  String name
  int age
}

def list = [new Person(name: 'John', age: 25), new Person(name: 'Major', age: 26)]

//对象 -> json字符串
def json = JsonOutput.toJson(list) 
println JsonOutput.prettyPrint(json) //格式化输出

//json字符串 -> 对象
def jsonslpuer = new JsonSlurper()
jsonSlpuer.parse(json)

xml:

final String xml = '''
    <response version-api="2.0">
        <value>
            <books id="1" classification="android">
                <book available="20" id="1">
                    <title>疯狂Android讲义</title>
                    <author id="1">李刚</author>
                </book>
                <book available="14" id="2">
                   <title>第一行代码</title>
                   <author id="2">郭林</author>
               </book>
               <book available="13" id="3">
                   <title>Android开发艺术探索</title>
                   <author id="3">任玉刚</author>
               </book>
               <book available="5" id="4">
                   <title>Android源码设计模式</title>
                   <author id="4">何红辉</author>
               </book>
           </books>
           <books id="2" classification="web">
               <book available="10" id="1">
                   <title>Vue从入门到精通</title>
                   <author id="4">李刚</author>
               </book>
           </books>
       </value>
    </response>
'''

def xmlSluper = new XmlSlurper()
def response = xmlSluper.parseText(xml)

println response.value.books[0].book[0].title.text()  //疯狂Android讲义
println response.value.books[0].book[0].@avuilable   //查看属性

//xml 查找操作
response.value.books.each { books ->
  books.book.each { book ->
      def author = book.author.text()
      if(author.equals('李刚')) {
        list.add(book.title.text())
      }
  }  
}
println list.toListString()

//深度遍历
response.depthFirst.findAll { book ->
    return book.author.text() == '李刚'
}

//广度遍历
response.value.books.children().findAll { node ->
    node.name() == 'book' && node@id == '2'
}.collect {
    return node.title.text()
}


/**
 * 生成xml格式数据
 * <langs type='current' count='3' mainstream='true'>
 * <language flavor='static' version='1.5'>Java</language>
 * <language flavor='dynamic' version='1.6.0'>Groovy</language>
 * <language flavor='dynamic' version='1.9'>JavaScript</language>
 * </langs>
 */
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder(sw) //用来生成xml数据的核心类
//根结点langs创建成功
xmlBuilder.langs(type: 'current', count: '3',mainstream: 'true') {
   //第一个language结点
   language(flavor: 'static', version: '1.5') {
       age('16')
   }
   language(flavor: 'dynamic', version: '1.6') {
       age('10')
   }
   language(flavor: 'dynamic', version: '1.9', 'JavaScript')
}
println sw

def langs = new Langs()
xmlBuilder.langs(type: langs.type, count: langs.count,
        mainstream: langs.mainstream) {
    //遍历所有的子结点
    langs.languages.each { lang ->
        language(flavor: lang.flavor,
                version: lang.version, lang.value)
    }
}
println sw
//对应xml中的langs结点
class Langs {
    String type = 'current'
    int count = 3
    boolean mainstream = true
    def languages = [
            new Language(flavor: 'static',
                    version: '1.5', value: 'Java'),
            new Language(flavor: 'dynamic',
                    version: '1.3', value: 'Groovy'),
            new Language(flavor: 'dynamic',
                    version: '1.6', value: 'JavaScript')
    ]
}
//对应xml中的languang结点
class Language {
    String flavor
    String version
    String value
}

10 面向对象

面向对象方面主要是注意几个和 java 的区别点:

  • groovy 中的类及成员变量默认类型都是 public 的
  • groovy 特有的 trait 接口,tarit 接口中可以有方法实现
  • groovy 中可以调用未定义的方法
/**
 * 定义类
 * 默认都是 public
 */
class Person implements Action {
    String name
    int age

    def increateAge(Integer years) {
        this.name += years
    }

    @Override
    String toString() {
       return "the name is ${name}, the age is ${age}"
    }

    @Override
    void eat() {

    }

    @Override
    void drink() {

    }

    @Override
    void play() {

    }
}

/**
 * 接口定义
 */
interface Action {
    void eat()
    void drink()
    void play()
}

/**
 * trait 有方法实现的接口
 */
trait DefaultAction {
    abstract void eat()
    void play() {
        println 'i can play'
    }
}

def person = new Person(name: 'Android', age: 26)
println person

调用未定义的方法主要通过下面几个途径实现:

  • methodMissing 方法
  • invokeMethod 方法
  • metaClass 注入方法和属性(类似 kotlin 的扩展属性,扩展方法)
/**
 * 定义类
 * 默认都是 public
 */
class Person  {
    String name
    int age

    def increateAge(Integer years) {
        this.name += years
    }

    /**
     * 当调用的方法不存在的时候会调用这个方法
     */
    def methodMissing(String name, Object args) {
        return "methodMissing the method is ${name}, the params is ${args}"
    }

    /**
     * 当调用的方法不存在的时候会调用这个方法,
     * 如果定义了 methodMissing 就不会调用 invokeMethod
     * @param name the name of the method to call
     * @param args the arguments to use for the method call
     * @return
     */
    def invokeMethod(String name, Object args) {
       return "invokeMethod the method is ${name}, the params is ${args}"
    }
}


def person = new Person(name: 'Android', age: 26)
println person.cry()
/**
 * 注入属性
 */
Person.metaClass.sex = 'male'
def person2 = new Person(name: 'Android', age: 26)
println(person2.sex)

person2.sex = 'famale'
println(person2.sex)

/**
 * 注入方法
 */
Person.metaClass.sexUpperCase = { ->
    sex.toUpperCase()
}

def person3 = new Person(name: 'Android', age: 26)
println person3.sexUpperCase()

//注入静态方法
Person.metaClass.static.createPerson = { String name, int age ->
    new Person(name: name, age: age)
}

def person4 = Person.createPerson("hello", 10)
println(person4.name + ": " + person4.age)

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

推荐阅读更多精彩内容