Gradle之Groovy

作爲一名Android開發者,每天使用AndroidStudio,對於項目中build.gradle文件肯定不陌生,裏面有各種各樣的配置。對於一些常用的配置我們肯定爛熟於心,不過有時候去看一些大廠的代碼的時候,經常會發現他們的項目中有很多的gradle的代碼,我們往往因爲不瞭解這些而對了解優秀的項目而帶來一些障礙。

百度百科:Gradle是一個基於Apache Ant和Apache Maven概念的項目自動化構建開源工具。它使用一種基於Groovy的特定領域語言(DSL)來聲明項目設置,目前也增加了基於Kotlin語言的kotlin-based DSL,拋棄了基於XML的各種繁瑣配置。

1 DSL語言介紹

domain specific language(領域特定語言 )

DSL語言特點:解決計算機某一特定領域的問題

核心思想:求專不求多

我們常見的UML,XML,HTML等都是DSL語言,他們都是專注於特定的領域來解決特定的問題。比如HTML就是爲了佈局UI。因爲專注,所以有很多優點比如代碼少,效率高。

2 groovy語言

啥是groovy

  • groovy是一種基於JVM的敏捷開發語言
  • 結合了Python Ruby Smalltalk等語言的強大特性
  • groovy可以和Java完美結合,可以使用Java所有的類庫,也能用於擴展現有代碼。

groovy的特性

  • 語法上支持動態類型,閉包等新一代語言的特性
  • 可以無縫集成左右已經存在的Java的類庫
  • 即支持面向對象編程,也支持面向過程編程

groovy的優勢

  • 它是一種更加敏捷的編程語言,可以用更少的代碼完成Java同樣的功能
  • 對於Java程序員來說,入門容易,功能強大
  • 即可以作爲編程語言,也可以作爲腳本語言

3 groovy環境搭建

官網:http://www.groovy-lang.org/

https://groovy.apache.org/download.html

  1. 安裝JDK
  2. 到官網下載groovySDK,解壓到合適位置
  3. 配置環境變量

無論mac/linux還是window都是這三步只不過每個平臺上的步驟不一樣,學啥語言的都跑不過這幾步。

4 Hello Groovy

學習一個語言基本都是從Hello World開始

開發一個Groovy程序可以使用intellij idea這個編譯器,https://www.jetbrains.com/idea/ 直接去官網下載社區版就可以了,社區版支持Groovy程序的開發。

Groovy和Java完全兼容,所以我們完全可以使用Java代碼來編寫Groovy程序

在intellij idea中新建一個Groovy程序(在新建項目面板的右上角,Groovy library選項中添加下載的groovySDK的路徑),在src文件夾下面新建一個Groovy的class類,寫下面Java代碼

class GroovyTest {
    public static void main(String[] args){
        System.out.print("Hello Groovy");
    }
}

可以直接運行,輸出: Hello Groovy

不過我們是來學Groovy語言的,當然用Groovy來寫會更簡單,簡單到啥程度呢,把上面代碼全刪了,寫下面一句。

print("Hello Groovy")

直接運行 輸出:Hello Groovy

看起來很爽啊!

5 Groovy 語法練習

5.1 變量

groovy中的變量包括 基本類型 ,對象類型,不過groovy中所有類型都是對象類型。基本類型也會被自動裝箱成對象類型比如:

int a = 2;
print(a.class)

輸出結果:class java.lang.Integer

變量的定義:

定義一個變量不僅可以使用強類型定義,也可以使用弱類型定義。比如即可以使用int,double這些來修飾一個變量,也可以直接用def來修飾一個變量,使用def修飾,系統會自動推導類型,比如:

def b = 3
println b.class
def c = 3.14
println c.class
def d = "groovy"
println d.class

輸出結果:
class java.lang.Integerclass java.lang.Integer
class java.math.BigDecimal
class java.lang.String

一般情況下,如果我們是自己在寫一個程序,使用def來定義一個變量會很簡單,如果程序還需要提供給外部人員使用,那使用強類型來定義比較好,不然外部人員可能會比較疑惑需要傳什麼類型的變量。

5.2 字符串

Java中是String

Groovy中是GString

5.2.1 Groovy常用的定義方式:
  • 使用單引號def name1 = 'i am name1'效果和java中一模一樣(不可擴展)
  • 使用三個引號def name = '''i am name''',使用三個引號的字符串我們可以在字符串內部保留字符串的格式,比如可以隨便換行
  • 使用雙引號定義字符串 def name3 = "i am name3"(可擴展)
def name1 = 'i am name1'

def name2 = '''i am name2
hello  name2
hai name2
'''
println(name2)
def name3 = "i am name3"
def name4 = "${name3} 哈哈"
println(name4)
//${}中可以是任意的表達式,比如
def sum = "2加3=${2+3}"
println(sum)
println(name3.class)
println(sum.class)

輸出:

i am name2
hello  name2
hai name2
i am name3 哈哈
23=5
class java.lang.String
class org.codehaus.groovy.runtime.GStringImpl

從上面的輸出內容還可以看出:一個雙引號定義的字符串的類型是java.lang.String,當經過${}符號運算過之後變成了org.codehaus.groovy.runtime.GStringImpl類型。雖然類型變了,在平時的程序中這兩個類型一般可以互相使用。

5.2.2 GString的操作符

GString的操作符比Java中的String中的方法多,只要來源是:

  • java.long.String
  • DefaultGroovyMethods
  • StringGroovyMethods(繼承DefaultGroovyMethods)包括普通類型的參數和閉包類型的參數

常用的普通類型參數:

def str = "hello groovy"
def str1 = "hello"
def str2 = "123"

println(str.center(15,'a'))//總長度15,在原字符串兩端加a
println(str.padLeft(15,'a'))//總長度15,在原字符串左邊加a
println(str>str1)
println(str[0])
println(str[0..1])
println(str.reverse())
println(str.capitalize())
println(str2.isNumber())
println(str2.toInteger())

輸出:

ahello groovyaa
aaahello groovy
true
h
he
yvoorg olleh
Hello groovy
true
123

5.3 邏輯控制

switch/case 和java中不一樣 比java中更強大

def x = 12
def res
switch (x){
    case 'string':
        res = 'string'
        break
    case [3,4,5,6,"haha"]://列表類型
        res = 'string'
        break
    case Integer:
        res = 'Integer'
        break
    case BigDecimal:
        res = 'BigDecimal'
        break
    case 9..30: //表示一個範圍
        res = 'string'
        break
   default: 'default'
}
println(res)

for循環

//循環一個範圍
for (i in 0..9){
    println(i)
}
//循環一個list
for (i in [3,4,5,6,7,8,9,0]){
    println(i)
}
//循環一個map
for (i in ["lily":18,"divad":19,"xiaoming":20]){
    println(i.key)
    println(i.value)
}

while循環、if/else和java中一樣

5.4 閉包

閉包是groovy最強大的功能之一

5.4.1 閉包的概念:就是一個代碼塊

閉包的定義和調用:

def closure = {println "hello groovy"}
//兩種調用的方法
closure.call()
closure()

閉包的參數:

def closure2 = { println "hello ${it}"}
closure2("groovy")
def closure1 = {String name,int age -> println "hello ${name},age ${age}"}
closure1("groovy",15)

會有一個默認的參數,可以使用it這個關鍵字來接收,如果有多個參數可以使用->來隔開

閉包的返回值

def closure2 = { return  "hello ${it}"}
def b = closure2("groovy")
println(b)

如果不定義return,默認返回的是null

5.4.2 閉包的使用

閉包與基本類型結合使用:

常用方法:

def x = 5
//求階乘
def jiecheng(int num){
    int res = 1
    //upto裏面實現了循環
    1.upto(num,{n -> res*=n})
    return res
}
//求階乘
def jiecheng1(int num){
    int res = 1
    num.downto(1){
        n -> res *= n
    }
    return res
}
//累加
def leijia(int num){
    int res = 1
    num.times {n -> res +=n}
    return res
}
println(jiecheng(x))
println(jiecheng1(x))
println(leijia(5))

閉包與字符串結合使用:

常用方法

def str = 'hello groovy 1 2 3'
//each 遍歷
str.each { String tem -> println(tem.capitalize()) }
//找到第一個滿足條件的 並返回
println str.find{ String tem -> tem.isNumber()}
//找到所有滿足條件的 並返回
println str.findAll(){ String tem -> tem.isNumber()}
//只要字符串中存在數字 就返回true
println str.any{ String s -> s.isNumber()}
//字符串每個元素都是數字 就返回true
println(str.every {String s -> s.isNumber()})
//蒐集所有字符 並大寫 放到list中返回
println str.collect {String s -> s.toUpperCase()}
5.4.3 閉包的進階

閉包關鍵變量 this, owner,delegate

def clouser = {
    println("this:" + this)
    println("owner:" + owner)
    println("delegate:" + delegate)
}
clouser.call()
輸出:
this:GroovyTest@741a8937
owner:GroovyTest@741a8937
delegate:GroovyTest@741a8937

從打印來看都是一樣的,那他們有什麼區別呢?

this:代表閉包定義處的類

owner:代表閉包定義處的類或者對象

delegate:代表任意對象 默認是owner

def outClouser = {
    def innerClouser = {
        println("this:" + this)
        println("owner:" + owner)
        println("delegate:" + delegate)
    }
    innerClouser.call()
}
outClouser.call()
輸出:
this:GroovyTest@306e95ec
owner:GroovyTest$_run_closure1@43dac38f
delegate:GroovyTest$_run_closure1@43dac38f

閉包的委託策略:

delegate可以動態的改變,改變之後可以讓一個對象指向另一個對象。

class Teacher{
    String name
    def nameStr = {"my name is ${name}"}
    @Override
    String toString() {
        return nameStr.call()
    }
}
class Student{
    String name
}
Teacher teacher = new Teacher(name: "teacher")
Student student = new Student(name: "student")
teacher.nameStr.delegate = student
teacher.nameStr.resolveStrategy = Closure.DELEGATE_FIRST
println teacher.toString()
輸出:
my name is student

5.5 常用的數據結構

5.5.1 列表

列表的定義

//java的方式定義
def list = new ArrayList()
//groovy的方式定義 它默認也是一個ArrayList
def list1 = [1,2,3]
//定義一個數組
def arr = [1,2,3] as int[]
int[] arr1 = [1,2,3]

列表的操作

增刪

def list = [3,2,4,1,5,9,7,8]
list.add(0)
//追加
list.leftShift(6)
//追加
list << 6
//刪除
//list.remove(1)
//list.removeAt(1)
//刪除所有偶數
list.removeAll {return it%2==0}
println(list)

排序操作

//java中的排序----------
def sortList = [3,5,2,1,-3,-6,-4]
//Collections.sort(sortList)
//println(sortList)
//自定義排序規則
//Comparator comparator = {a,b->a==b?0:Math.abs(a)>Math.abs(b)?1:-1}
//Collections.sort(sortList,comparator)
//println(sortList)

//groovy中的排序-----------
sortList.sort()
//自定義排序規則
sortList.sort(){a,b->a==b?0:Math.abs(a)>Math.abs(b)?1:-1}
println(sortList)
//字符串列表
def stringList = ['hello','ab','a','cde','groovy']
stringList.sort(){it -> return  it.size()}
println(stringList)

def findList = [5,6,3,2,1,9,8]
//查找第一個奇數
def res = findList.find(){return it%2 == 1}
//查找所有的奇數
def res1 = findList.findAll(){return it%2 == 1}
//判斷是否有奇數
def res2 = findList.any(){return it%2 == 1}
//判斷是不是全是奇數
def res3 = findList.every(){return it%2 == 1}
println(res3)
println(findList.min())
println(findList.max())
println(findList.min{return  Math.abs(it)})
//統計查找偶數的個數
def num = findList.count{ return it%2==0 }
println(num)
5.5.1 Map

Map的定義和使用

//java方式
def map = new HashMap()
//groovy方式 
def map1 = ['lily':15,'jack':16,'divad':17]
//查找元素
println(map1['lily'])
//添加元素
map1.xiaoming = 18
println(map1.toMapString())
//添加不同類型的元素
map1.sub = ['a':1,'b':2]
println(map1.toMapString())

groovy中的Map默認是Java中LinkedHashMap

Map的常用操作

def map = ['lily':15,'jack':16,'divad':17,'xiao':14]
//遍歷
map.each {def person -> println "key:${person.key} value:${person.value}"}
map.each {key,value -> println "key:${key} value:${value}"}
//有下標的遍歷
map.eachWithIndex {def person ,int index -> println "key:${person.key} value:${person.value} index:${index}"}
map.eachWithIndex{key,value,index -> println "key:${key} value:${value} index:${index}"}

//查找第一個年齡大於15的
def res = map.find{def person -> person.value>15}
//查找所有年齡大於15的
def res1 = map.findAll{def person -> person.value>15}
//統計大於年齡15的個數
def num = map.count {return it.value>15}
//查找並分組
def group = map.groupBy {return  it.value>15?'man':'child'}
println(group.toMapString())

//排序
def sort = map.sort{ def v1,def v2 ->
    return v1.value == v2.value?0:v1.value>v2.value?1:-1
}
println(sort)

5.6 範圍 Range

Range是一個輕量級的list,在有些簡單的地方使用會比list更加方便

Range的定義和使用

def range = 1..10
println(range[0])
println(range.from)
println(range.to)
println(range.contains(11))
range.each {println(it)}
for (i in range) {
    println(i)
}
def res = getGrade(85)
println(res)
def getGrade(int num){
    def result
    switch (num){
      case 0..60:
          result = '及格'
            break
        case 60..80:
            result = '良好'
            break
        case 80..100:
            result = '優秀'
            break
    }
    return  result
}

5.7 面向對象

類默認都是public的

interface IAction {
     void eat()

    void drink()
}
class Person implements IAction{
    String name
    int age
    def increaseAge(int num){
        this.age += num
    }

    @Override
    void eat() {

    }
    @Override
    void drink() {

    }
}

def person = new Person(name: 'lily',age: 15)
person.increaseAge(10)
println("name: ${person.name} age: ${person.age}")

groovy中元編程

當調用一個類的方法的時候:

  1. 該類中是否有此方法 有直接調用,沒有去MetaClass中查找是否有
  2. MetaClass中有調用MeatClass中的方法,沒有看是否重寫了methodMissing()方法,寫了調用該方法,沒寫,看是否重寫了invoke()方法
  3. 寫了自行invoke方法,沒寫拋出異常(MissingMethodExecption)

動態添加屬性或者方法,可以擴展一些引入的第三方包中的類

def person = new Person(name: 'lily',age: 15)
person.increaseAge(10)
person.cry()
//給一個類動態注入一個屬性
Person.metaClass.sex = 'male'
def person1 = new Person(name: 'lily',age: 15)
println(person1.sex)
//給一個類動態添加一個方法
Person.metaClass.sexUpperCase = { -> sex.toUpperCase()}
def person2 = new Person(name: 'lily',age: 15)
println(person2.sexUpperCase())
//給一個類動態添加一個靜態方法
Person.metaClass.static.createPerson = {
    name,age -> return new Person(name:name,age: age)
}
def person3 = Person.createPerson('lily',15)
println("name:${person3.name}")

6 Groovy高級語法

6.1 groovy 對 json的操作

groovy中自帶的操作json的方式非常簡單

def list = [new Person(name: 'lily',age: 15),new Person(name: 'jack',age: 16)]
//對象轉成json
String json = JsonOutput.toJson(list)
println(json)
//json轉成對象
def jsonSlurper = new JsonSlurper()
println jsonSlurper.parseText(json)
//parse方法有很多重載的方法,可傳入不同的值
jsonSlurper.parse()

jsonSlurper.parse()方法有很多重載的方法,可傳入不同的值

6.2 groovy處理xml

解析xml的數據

final String xml = '''<apps>
    <app>
        <id>1</id>
        <name>Google Maps</name>
        <virsion>1.0</virsion>
    </app>
    <app>
        <id>2</id>
        <name>Chrome</name>
        <version>2.1</version>
    </app>
    <app>
        <id>3</id>
        <name>Google Play</name>
        <version>2.3</version>
    </app>
</apps>
'''
def xmlSlurper = new XmlSlurper()
//返回的是xml的根節點
def apps = xmlSlurper.parseText(xml)
println(apps.app[0].name.text())
//深度遍歷
def  res = apps.depthFirst().findAll { app ->
    return app.name.text()
}
def res1 = apps.children().findAll { app -> app.name() == 'app' }.collect {
    app -> return app.name.text()
}
println(res)
println(res1)

生成xml的數據

import groovy.xml.MarkupBuilder

def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder()
xmlBuilder.apps(type:'1'){
     app(){
         id(1)
         name('Google Maps')
         version(2.0)
     }
    app(){
        id(2)
        name('Chrome')
        version(1.0)
    }
    app(){
        id(3)
        name('Google Play')
        version(3.0)
    }
}
println(sw)

通過類自動生成xml

import groovy.xml.MarkupBuilder

def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder()
class apps{
    String type = '1'
    def apps = [new appsub(id: 1,name: 'Google Play',version: '1.0'),
                new appsub(id: 1,name: 'java',version: '2.0'),
                new appsub(id: 1,name: 'Google map',version: '3.0')]
}
class appsub{
    int id
    String name
    String version
}
def apps = new apps()
xmlBuilder.apps(type:apps.type){
    apps.apps.each { sub ->
        appsub(){
            id(sub.id)
            name(sub.name)
            version(sub.version)
        }
    }
}
println(sw)

6.3 groovy處理文件

所有java中的處理文件的方式都可以使用
groovy中也有自己的封裝的簡單的方法

讀取項目跟目錄下的一個文件並遍歷

def file = new File('../MyGroovy.iml')
file.each {line -> println(line)}

讀取內容爲一個text

def text = file.getText()
println(text)

讀取部分內容

def reader = file.withReader { reader ->
    char[] buffer = new char[100]
    reader.read(buffer)
    return buffer
}
println(reader)

文件寫入

def copy(String fromDir,String toDir){
    try {
        //創建目標文件
       def toFile = new File(toDir)
        if(!toFile.exists()){
            toFile.createNewFile()
        }
        //開始copy
        def fromFile = new File(fromDir);
        if(fromFile.exists()){
            fromFile.withReader { reader ->
                def  lines = reader.readLines()
                toFile.withWriter { write->
                    lines.each {
                        line->
                            write.append(line + "\r\n")
                    }
                }
            }
        }
        return true
    }catch (Exception e){
        e.printStackTrace()
    }
    return false
}
def copres = copy('../MyGroovy.iml','../MyGroovy.iml2')
println(copres)

對象的保存和讀取

//保存對象
def saveObject(Object obj,String path){
    try {
        //創建目標文件
       def toFile = new File(path)
        if(!toFile.exists()){
            toFile.createNewFile()
        }
        toFile.withObjectOutputStream {out->
            out.writeObject(obj)
        }
        return true
    }catch (Exception e){
        e.printStackTrace()
    }
    return false
}
//讀取對象
def readObj(String path){
    def obj = null
    try {
        def file = new File(path)
        if(file==null||!file.exists()) return null
        file.withObjectInputStream {
            input->
                obj = input.readObject()
        }
        return obj
    }catch (Exception e){
        e.printStackTrace()
    }
    return null
}
def person = new Person(name: '大海',age: 15)
def res = saveObject(person,'../person.bin')
println(res)
def personRes = (Person)readObj('../person.bin')
println(personRes.name)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章