Gradle 之 Groovy 的进阶

Posted Android实用开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gradle 之 Groovy 的进阶相关的知识,希望对你有一定的参考价值。


好!抖擞精神,此时此刻请允许我吟诗两句:“纸上得来终觉浅,绝知此事要躬行。” 也希望我们以后如果深入理解其中的道理,必须要亲自实践才行。下面进入正题,本文主要介绍 Groovy 中对集合的操作,以及对 xml 和 json 数据格式的解析。


我们都知道在进行数据处理的过程中,对集合的操作是必不可少的。在 Groovy 这种动态语言中,对集合的操作比在 Java 中要简易方便强大的多。上菜品尝一下:


定义一个集合或数组:

//定义一个list集合
def list = new ArrayList() def list = [1,2,3,4,5]
//定义一个数组
def list = [1,2,3,4,5] as int[] int[] list = [1,2,3]

你可能会感觉这个定义和 Java 相比并没有什么优势,是的,请慢慢向下看。我们对数据集合的操作无非是增删改查。接下来看一下如何操作的:

//增加
def listNo = [-1,36,-2,-23,20]
listNo.add(-1)
println(listNo.toListString()) //[-1, 36, 9, -2, -23, 20, -1]
listNo << 2 //在集合里面尾部添加一个数字 2,与 listNo.leftShift(2) 意义相同
println(listNo.toListString())//5 << listNo 语法不对,没有意义和 listNo >> 5 语法不对报错
def integers = listNo + [3, 18]println integers.toListString()// 集合可以直接相加,集合也可以直接加上一个对象

//删除
println(listNo.remove((Object)(-1)))//true删除某个对象,只会删除第一个对象
println(listNo.toListString())//[36, 9, -2, -23, 20, -1]
println listNo -[2,-2] //[9, -23, 20, -1]
println listNo.removeElement(36)//true,删除36这个int对象

//修改
listNo[0] = 2
println(listNo.toListString()) //[2, 9, -2, -23, 20, -1]

上面介绍了增删改,是不是很方便啊?!嗯,不管是不是,看看如何查吧

def listNo = [-1,36,9,-2,-23,20]
println(listNo.find { it -> return it % 2 == 1 })//9
println(listNo.findAll { it -> return it % 2 == 0 }.toListString())//[36, -2, 20]
println(listNo.any {return it % 2 == 1})//true
println(listNo.every{return it % 2 == 1})//false
println(listNo.min()) //-23最小值
println(listNo.max()) //36最大值
println(listNo.count {return it>0}) //3统计list中满足某条件的数量

查数量、查满足条件的一条数据、查满足条件的所有数据,是不是很666。接下来我们来简单看一下集合的排序,Java 中集合的排序借助于 Comparable 或者 Comparator,在 Groovy 中则不需要这样。

//定义一个list集合
def nums = [-9,1,2,-3,4,-5,7]
//=============java中===========
//定义排序规则,按照绝对值从小到大排序
Comparator comparator ={a,b -> a==b ? 0 : Math.abs(a)>Math.abs(b) ? 1 : -1} Collections.sort(nums,comparator)
//从小到大排序
Collections.sort(nums)
//============groovy===================
//从小到大排序
nums.sort()
//定义排序规则,按照绝对值从小到大排序
nums.sort {a,b -> a==b?0:Math.abs(a)>Math.abs(b)? -1 : 1}
println nums

上面介绍了 List 集合的操作,接下来看一下 Map 的定义和相关操作

//定义
// 可以在定义的后面加上比如def map = [name:'Ade','age':18] as HashMap,
// 或者HashMap map = [name:'Ade','age':'18']
def map = [name:'Ade','age':'18']
//mapkey可以不带带引号,编译的时候默认加上了''key值不可变
println(map.get('name'))//Ade
println(map['age'])//18

//查找
println map.findAll {it -> it.key}//[name:Ade, age:18]

//增加
map.collage = 'QinHua'
println map.toMapString()//[name:Ade, age:18, collage:QinHua]
map.add = [a:1,b:2]
println map.toMapString()
//map不仅能添加同类型的元素还能添加不同类型的元素
// [name:Ade, age:18, collage:QinHua, add:[a:1, b:2]]
println map.getClass()
//class java.util.LinkedHashMap,如果一开始想定义固定的类,
// 此处不能使用.class获取类的类型,因为这个是找map对应key为class的值

在 Map 的遍历中我们常用两个闭包 each 和 eachWithIndex,each 不含角标,eachWithIndex 包含角标参数,例子如下

map.each {def person -> println "The key is ${person.key},The value is ${person.value}"} //The key is name,The value is Ade //The key is age,The value is 18

map.eachWithIndex { Map.Entry<String, String> entry, int i -> println "The position is ${i} ,The key is ${entry.key},The value is ${entry.value}"} //The position is 0 ,The key is name,The value is Ade //The position is 1 ,The key is age,The value is 18

//上面的eachWithIndex也可以简写成
//map.eachWithIndex { def key,value,index-> println "The position is ${index},The key is ${key},The value is ${value}" } //The position is 0,The key is name,The value is Ade //The position is 1,The key is age,The value is 18

有的时候我们需要查找满足条件的数一据,就像List一样查找一部分数据,比如查找一组学生中成绩及格的同学的名称,以及分组操作,Show 代码

def studentMap = [1:[name:'Ade',score:90,sex:'male'],                  
                 2:[name:'Lily',score:69,sex:'female'],                  
                 3:[name:'Lucy',score:58,sex:'female'],                  
                 4:[name:'Ha',score:90,sex:'male']]

def all = studentMap.findAll { def student ->
   return student.value.score >= 60
}.collect
{
   return it.value.name
} println(all.toListString())//[Ade, Lily, Ha]

def groupBy = studentMap.groupBy { def student ->
   return student.value.score >= 60 ? '及格'
: '不及格'
} println(groupBy.toMapString())
//[及格:[1:[name:Ade, sco
re:90, sex:male], 2:[name:Lily, score:69, sex:female],
// 4:[name:Ha, score:90, sex:male]], 不及格:[3:[name:Lucy, score:58, sex:female]]]

Map 的排序

//排序(按照从大到小排序,a1>a2?-1:1)
def sort = studentMap.sort { def stu1, stu2 ->    Number score1 = stu1.value.score    Number score2 = stu2.value.score    return score1 == score2 ? 0 : score1>score2 ? -1:1} println sort.toMapString()
//[1:[name:Ade, score:90, sex:male], 4:[name:Ha, score:90, sex:male],
// 2:[name:Lily, score:69, sex:female], 3:[name:Lucy, score:58, sex:female]]

接下来补充一个简单的集合------范围

//返回从1开始到10,包含边界
def range = 1..10
println range.contains(10) // true
println range.contains(1) //true
println range.from // 1
println range.to   // 10
println range.toListString() // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
//如果要范围从1开始到10,不包含10,则可以如下写
def range1 =1..<10

以上我们了解了基本数据处理和常用集合的使用,接下来了解一下 Groovy 中类的定义和接口的定义。


Groovy 中默认类和方法都是 public 的,并且是实现了 GroovyObject 接口。如果一个类里面重写了 invokeMethod 这个方法, 一个方法找不到的时候就会用此方法来调用来代替你所调用的方法,而不会抛出 MethodMissingException 异常。如果类里面重写了 invokeMethod 和 methodMissing,类找不到的时候会调用 methodMissing 方法

     * 注:这些方法的调用都是在运行时调用,编译期间不会判断是否有此方法,而 java 中在编译时期就知道是否有该方法


类的定义

package variable

class Person implements Skill,SecondSkill{    
   String name    Integer age
       
   //def来修饰方法 返回值默认是当前类    def increaseAge(Integer years){        
       this.age += years    }    
   
   @Override    void work() {    }    
   
   @Override    void eat() {    }            @Override    Object invokeMethod(String s, Object o) {        
       return "The method is ${s},the params is ${o}"    }    def methodMissing(String s, Object o) {        
       return "The missmethod is ${s},the params is ${o}"    } }

接口的定义

package variable
/** * 接口中不允许定义非public修饰的方法,默认都是public */

interface Skill {    
   void work() }

trait类的定义,类似于接口,不过trait类里面可以有默认的实现,像设计模式中的接口适配模式,定义一个接口里面有很多要实现的方法。然后再定义一个适配器类实现这个接口,里面有一些方法是空实现的,然后再定义一个类来继承这个适配器类,就只需要实现里面的部分方法就可以了


package variable

trait SecondSkill {    
   abstract void eat()
   
   void play(){        println 'I can play football.'    } }

类的使用

package variable

//无论是直接类名.还是使用get/set方法都是实质上调用的该对象的get/set方法
def person = new Person(name: 'Ade',age: 27) println "My name is ${person.name},I'm ${person.age} years old."
person.increaseAge(1) println "My name is ${person.getName()},I'm ${person.getName()} years old."

请注意!

请注意!

请注意!

Groovy 强大的点来了,Groovy 之类(metaClass相关操作)的属性、方法动态添加,一般注入防范和属性只能在当前类里面进行使用,但是也可以通过 ExpandoMetaClass.enableGlobally() 使得注入的类和属性在全局都可以使用。


用处:比如 java 中引用第三方的包,里面的方法又不全然后只能继承重写里面的方法,但是如果这个类是 final 的话就无法继承重写方法,这中方式就可以处理这个问题。来个例子吧!

Person.metaClass.sex = 'male'
def person = new Person(name: 'Ade',age:
18)
println person.sex //male
person.sex = 'female'
println "The new sex is ${person.sex}" //The new sex is female

Person.metaClass.sexUpperCase = {-> sex.toUpperCase()}
println person.sexUpperCase() //FEMALE

//注入一个静态方法
Person.metaClass.static.createPerson = {    String name,Integer age ->
   
new Person(name:name,age: age) }
def person1 = Person.createPerson('Groovy', 10)
println "My name is ${person1.name},I'm ${person1.age} years old."
//My name is Groovy,I'm 10 years old.

全局注入,比如我们对 String 类增加一个全局可用的扩展方法,将字符串转化成逆序大写

class AppManager {    
static void init(){        ExpandoMetaClass.enableGlobally()        String.metaClass.static.reverseUpperCase = {            
           value -> value.toString().reverse().toUpperCase()        }    } } //===========使用============
class MainClass {    
static void main(String[] args) {        AppManager.init()        String s =String.reverseUpperCase('Ade')        println s //
EDA    } }

小伙伴们,看了这么多累了吧!要不休息一下,来张青春妩媚的图养养眼啊



O(∩_∩)O哈哈~ 是不是一下勾起童年的回忆,来张正常的吧



有木有心动的感觉啊?!心动不如行动,学好技术,迎娶白富美!接下来简单了解一下 Groovy 中对 json、 xml 以及文件的处理。


json 数据的操作之实体对象转换成 json 字符串

def list = [new Person(name: 'Ade',age: 27),new Person(name: 'Vivian',age: 27)]
//def json = toJson(list)
def json = JsonOutput.toJson(list)//与上面一句一样的意思
println(json) println(JsonOutput.prettyPrint(json))

json 数据的操作之 json 字符串转换成实体对象

def  jsonSlurper = new JsonSlurper()
List<Person> parse = jsonSlurper.parseText(json)
println parse.toListString()

在 java 中的 xml 解析一般分为两种,DOM 解析和 SAX 解析,后者相对节省内存,但是还是很麻烦。在 Groovy 中,对 xml 格式的数据进行解析十分方便,举例说明

//''''''用来定义带格式的字符串
def xml ='''    <response version="2.0" encoding="UTF-8">        <clazz id='1'>            <note>                <to id = '1'>Beijing</to>                <from>Nanjing</from>                <name>Ade</name>                <body>Say Hello</body>            </note>            <note>                <to id = '3'>Shanghai</to>                <from>Beijing</from>                <name>Lily</name>                <body>Say Hello to Groovy</body>            </note>            <note>                <to id = '3'>Shanghai</to>                <from>Nanjing</from>                <name>Vivian</name>                <body>Say Hello</body>            </note>          </clazz>          <clazz id='2'>            <note>                <to id = '3'>Shanghai</to>                <from>Hangzhou</from>                <name>Ade</name>                <body>Say Hangzhou</body>                <test>                    <testName>Test Name</testName>                </test>            </note>          </clazz>    </response>''' def xmlSluper = new XmlSlurper() def response = xmlSluper.parseText(xml) println response.clazz[0].note[0].to   //Beijing println response.clazz[0].note[0].to.@id   //1 def list =[] response.clazz.each
{    clazz ->clazz.note.each{        note -> if(note.name == 'Ade'){list.add(note.body)}    } } println list.toListString() //[Say Hello, Say Hangzhou] //所谓深度遍历就是跨界层遍历
//def lists = response.clazz.'**'.findAll{// 同样代表深度遍历
def lists = response.clazz.depthFirst().findAll{    test -> return test.testName == 'Test Name' }.collect
{    test -> return test.testName }println lists.getClass() //class java.util.ArrayList println lists.toListString() //[Test Name]
//广度遍历,就是遍历同一级别下面的所有,'*'children()是同一个概念
//def s = response.clazz.'*'.findAll
{ def s = response.clazz.children().findAll{    note -> return note.name == 'Vivian' }.collect{    node -> return node.from }

println s.getClass()  //class java.util.ArrayList println s.toListString()  //[Nanjing]

解析 xml  数据是需要 XmlSlurper 解析类,并调用其parseXXX方法。生成 xml 则需要借助MarkupBuilder 类,例子如下:

def sw = new StringWriter()
def xml = new MarkupBuilder(sw)

xml.clazz(id:'2'){
    note(){        
       to(id:'3','Shanghai')        from('Hangzhou')        name('Ade')        body('Say Hangzhou')        test(){            testName('Test Name')        }    } } println sw//生成下面的xml
       <clazz id='2'>    
       <note>            <to id = '3'>Shanghai</to>        
           <from>Hangzhou</from>        
           <name>Ade</name>        
           <body>Say Hangzhou</body>        
           <test>                <testName>Test Name</testName>            </test>        </note>  </clazz>

上面是生成静态的 xml 数据,那如何动态生成 xml 数据呢?

//动态生成xml
class Clazz{    String id ='2'    def notes = [new Note(to: new To(id: '3',value: 'Shanghai'),                    from: new From(value: 'Hangzhou'),                    name: new Name(value: 'Ade'),                    body: new Body(value: 'Say Hangzhou')),          
                 new Note(to: new To(id: '4',value: 'Beijing'),                    
                    from: new From(value: 'Nanjing'),                    name: new Name(value: 'Ade'),                    body: new Body(value: 'Say Beijing'))                ] }
                   
class Note{    To to    From from    Name name    Body body }
class To{    String id    String value}
class From{    String value
}
class Name{    String value
}
class Body{    String value
} def sw = new StringWriter() def xmlBuilder = new MarkupBuilder(sw) def clazz = new Clazz() xmlBuilder.clazz(id:clazz.id){    clazz.notes.each {        singleNote -> note(){        //注意此处不能有换行符            to(id:singleNote.to.id,value: singleNote.to.value)+from(value: singleNote.from.value)+name(value: singleNote.name.value) +body(value: singleNote.body.value)        }    } } println sw

相信你通过对上面的学习已经了解了对 json 和 xml 数据的解析和操作。接下来看一下对文件的处理,这也是后期 Gradle 打包过程中所用到的基础知识。

def file = new File('../../TestGroovy.iml')
//原文本一行一行输出
file.eachLine {    line -> println line }
//原文本输出
def text = file.text //file.getText()
println(text)//获取的数据是整个字符串集合
def lines = file.readLines()
println(lines.toListString())

//读取文件中前10个字符
def reader = file.withReader {reader ->        
   char[] buffer = new char[10]
   reader.read(buffer)        
   return buffer }
   
println(reader.getClass())
println(reader)
   
//
直接把文件里面的内容覆盖了(如果按照下面操作了,可以找历史记录返回正常文件)
def writer=file.withWriter {writer ->    writer.write('Ade')    
   return writer }
println(writer.getClass())
println(writer)

println(copyFile('../../TestGroovy.iml','../../TestGroovy2.iml'))
//拷贝文件
def copyFile(String sourceFile,String targetFile){    
   try{
       def sFile = new File(sourceFile)        
       if (!sFile.exists()) return        def tFile = new File(targetFile)        
       if (!tFile.exists()){            tFile.createNewFile()        }        sFile.withReader {reader ->                
           def lines = reader.readLines()                tFile.withWriter {writer ->                    lines.each {                        line ->writer.writeLine(line)                    }             }        }        
       return true    }catch (Exception e){        e.printStackTrace()    }    
       return false

}
//对象的写读

def person = new Person(name: '大猪蹄子',age: 380) writeObject(person,'../../person.bin')
def object = (Person)readObject('../../person.bin')
println("My name is ${object.name},I'm ${object.age}") //My name is 大猪蹄子,I'm 380

def writeObject(Object o,String path){    
try {        
   def file = new File(path)        
   if (!file.exists()){            
       file.createNewFile()        }        
   file.withObjectOutputStream {            outPutStream -> outPutStream.writeObject(o)        }        
       return true    }catch (Exception e){        e.printStackTrace()    }        
   return false    
}

def
readObject(String path){    
   try {        
       def file = new File(path)        
       if (!file.exists()){            
           return null        }        Object o = file.withObjectInputStream {            inputStream-> inputStream.readObject()        }        
       return o    }catch (Exception e){        e.printStackTrace()    }    
   return null
}

好,Groovy中基础我们就说的这里了,和Java对比一下:

  1. 写法上没有java那么多的限制 
    比如:;分号的书写,可以写也可以不写;return语句的意义,有事可以不写return。 Groovy相同的功能提供了大量的语法糖实现。

  2. 在功能上,对java已有的功能进行了很多的扩展
    比如json文件和xml文件的解析,文件的处理等等,再比如可以为系统类运行时添加一些方法和属性。

  3. Groovy可以编写应用,也可以编写脚本


最后希望本篇大家会喜欢。最后后台回复 “Groovy小资料” 领取小资料一份。






以上是关于Gradle 之 Groovy 的进阶的主要内容,如果未能解决你的问题,请参考以下文章

Gradle 之语言基础 Groovy

Gradle入门之Groovy语法

Gradle入门之Groovy元编程

Gradle系列学习:初识Gradle之Groovy基础Gradle从入门到实战 - Groovy基础

Gradle学习笔记之Groovy

Android知识要点整理(15)----Gradle 之Groovy语言基础