Gradle入門系列(一)——groovy基礎語法

groovy基礎語法

1、變量

一、類型

對象類型、基本類型(本質是對象類型)java

int x = 0
println x.class
double y = 3.14
println y.class
複製代碼

輸出:編程

class java.lang.Integer
class java.lang.Double
複製代碼

結論: 從log輸出能夠得出,groovy中實質上是沒有基本類型的,本質是java中的裝箱對象類型。api

二、定義

強類型定義方式、弱類型def定義方式數組

def x_1 = 11
println x_1.class
def y_1 = 3.1415
println y_1.class
def name = 'Android'
println name.class
複製代碼

輸出:數據結構

class java.lang.Integer
class java.math.BigDecimal
class java.lang.String
複製代碼

2、字符串

String、GString閉包

一、經常使用的三種定義方式

// 單引號:與java中的String是同樣的
def name = 'a single \'a\' string'
println name.class
// 三引號:能夠直接指定格式(如:換行,不須要加\n,代碼表示上也不須要用+號拼接)
def thupleName = '''three single string'''
println thupleName.class
// 三引號:須要每行文字聲明不一樣行(即:三引號後沒關係接文字內容),能夠用\。
def thupleName1 = '''\ line one line two line three'''
println thupleName1
// 雙引號:可擴展字符串(即:可包含變量、表達式等)
def doubleName = "this a common String" // String
println doubleName.class
def doubleName1 = "Hello: ${name}" // GString
println doubleName1.class
複製代碼
// 單引號
class java.lang.String
// 三引號
class java.lang.String
line one
line two
line three
// 雙引號
class java.lang.String
class org.codehaus.groovy.runtime.GStringImpl
複製代碼

二、新增操做符

方法來源:java.lang.String、DefaultGroovyMethods、StringGroovyMethods(普通類型的參數、閉包類型的參數)函數

def str = "groovy"
def str2 = "gro"
// center(numberOfChars, padding):使用padding對已有字符串兩邊進行填充
// center(numberOfChars):使用空格對已有字符串兩邊進行填充
println str.center(8,'a')
// padLeft(numberOfChars, padding):使用padding對已有字符串左邊進行填充
println str.padLeft(8,'a')
// 比較:可使用>、<符號來直接比較,而不須要使用compareTo()
println str > str2
// 獲取字符:string[index](至關於string.getAt(index))
println str[0]
println str[0..1]
// 減去字符串:能夠直接使用-號,效果與minus()一致
println str - str2 // str.minus(str2)
// 倒序
println str.reverse()
// 首字母大寫
println str.capitalize()
// 判斷是不是數字
println str.isNumber()
複製代碼

輸出:this

// center
agroovya
// padLef
aagroovy
// str > str2
true
// str[0]
g
// str[0..1]
gr
// str - str2
ovy
// reverse
yvoorg
// capitalize
Groovy
// isNumber
false
複製代碼

3、新增API講解

邏輯控制:順序邏輯(單步往下執行)、條件邏輯(if/else、switch/case)、循環邏輯(while、for)spa

// ============= 條件邏輯 =============
def x = 1.23
def result
switch(x){
  case 'foo':
    result = 'found foo'
    break
  case [4,5,6,'inlist']: // 列表
    result = 'list'
    break
  case 12..30: // 範圍
    result = "range"
    break
  case Integer:
    result = 'integer'
    break
  case BigDecimal:
    result = 'big decimal'
    break
 default:
    result = 'default'
    break
}
println result

// ============= 循環邏輯 =============
def sum = 0
// 對範圍的for循環
for(i in 0..9){sum += i}
// 對List的循環
for(i in [0,1,2,3,4,5,6,7,8,9]){sum += i}
// 對Map的循環
for(i in ["lili":1, "luck":2, "xiaoming":3]){
  sum += i.value
}
複製代碼

輸出:rest

// x = 1.23
big decimal
// x = 4
list
複製代碼

groovy閉包講解

1、基礎

閉包概念(定義、調用)、閉包參數(普通參數、隱式參數)、閉包返回值(老是有返回值的)

// ============= 閉包概念 =============
// 定義
def clouser = {println 'Hello groovy!'}
// 調用1:
clouser.call()
// 調用2:
clouser()

// ============= 閉包參數 =============
// 普通參數
def clouser = {String name, int age -> println "Hello ${name}, my age is ${age}"}
clouser('groovy!', 18) // clouser.call('groovy!', 18) 
// 隱式參數(it是全部閉包都擁有的默認參數,當有顯式聲明參數時,it失效)
def clouser = {println "Hello ${it}"}
clouser('groovy!')

// ============= 閉包返回值 =============
def clouser = {return 'Hello, groovy!'} // 返回 Hello, groovy
def result = clouser()
println result

def clouser = {println 'Hello groovy!'} // 返回 null
def result = clouser()
println result
複製代碼

2、使用

閉包的用法:與基本類型的結合使用、與String結合使用、與數據結構結合使用、與文件等結合使用

// ============= 與基本類型的結合使用 =============
int x = fab(5)
println x
// 用來求指定number的階乘
int fab(int number){
  int result = 1
  1.upto(number, {num -> result *= num}) // upto()是DefaultGroovyMethods中封裝好的方式
  return result
}
int fab2(int number){
  int result = 1
  number.downto(1){       // 閉包能夠不寫在括號內,能夠寫在括號外
    num -> result *= num
  }
  return result
}
// 從0循環到number
int cal(int number){
  int result = 1
  number.times { // times(Closure)只接收一個閉包,把閉包寫到括號外,括號能夠省略
    num -> result += num
  }
  return result
}

// ============= 與String結合使用包參數 =============
String str = 'the 2 and 3 is 5'
// each:遍歷每一個字符
str.each {
  String temp -> print temp
}
// find:查找符合條件的第一個
println str.find {
  String s -> s.isNumber()
}
// findAll:查找符合條件的全部字符
def list = str.findAll {
  String s -> s.isNumber()
}
println list.toListString()
// any:遍歷每一個字符,只要知足條件就返回true
def result= str.any {
  String s -> s.isNumber()
}
println result
// every:遍歷每一個字符,全部都要知足條件纔會返回true
println str.every {
  String s -> s.isNumber
}
// collect:遍歷每一個字符,通過閉包處理後,添加進list中返回
def list = str.collect { it.toUpperCase() }
println list.toListString()

// ============= 與數據結構結合使用 =============
// ============= 與文件等結合使用 =============
// 後續篇章中會涉及

複製代碼

輸出:

// ============= 與String結合使用包參數 =============
// each
the 2 and 3 is 5
// find
2
// final All
[2, 3, 5]
// any
true
// every
false
// collect
[T, H, E,  , 2,  , A, N, D,  , 3,  , I, S,  , 5]
複製代碼

3、進階

閉包關鍵變量(this、owner、delegate)

// this == owner == delegate
def scriptClosure = {
  println "scriptClosure this:"+this // 表明閉包定義處的類
  println "scriptClosure owner:"+owner // 表明閉包定義處的類或者對象
  println "scriptClosure delegate:"+delegate // 代碼任意對象,默認與owner一致
}
scriptClosure.call()

// this != owner == delegate
def nestClosure = {
  def innerClosure = {
    prinln "innerClosure this:"+this
    prinln "innerClosure owner:"+owner
    prinln "innerClosure delegate:"+delegate
  }
  innerClosure.call()
}

// this != owner != delegate
def nestClosure = {
  def innerClosure = {
    prinln "innerClosure this:"+this
    prinln "innerClosure owner:"+owner
    prinln "innerClosure delegate:"+delegate
  }
  innerClosure.delegate = new Person() // 手動修改delegate的值
  innerClosure.call()
}
複製代碼

輸出

// this == owner == delegate
scriptClosure this:variable.closurestudy@2ef3eef9
scriptClosure owner:variable.closurestudy@2ef3eef9
scriptClosure delegate:variable.closurestudy@2ef3eef9

// this != owner == delegate
innerClosure this:variable.closurestudy@2ef3eef9
innerClosure owner:variable.closurestudy$_run_closure2@402bba4f
innerClosure delegate:variable.closurestudy$_run_closure2@402bba4f

// this != owner != delegate
innerClosure this:variable.closurestudy@2ef3eef9
innerClosure owner:variable.closurestudy$_run_closure2@402bba4f
innerClosure delegate:variable.Person@795cd85e
複製代碼

結論:

  • 在大多數據狀況下,this、owner、delegate的值是同樣的。
  • 在閉包中定義閉包時,this與owner的值是不同的。(this指的是閉包定義處的類對象,owner指的是閉包定義處類中的閉包對象)
  • 在手動修改了閉包delegate時,owner與delegate的值纔會不同。

閉包委託策略(Closure.OWNER_FIRST、Closure.OWNER_ONLY、Closure.DELEGATE_FIRST、Closure.DELEGATE_ONLY)

class Studen{
  String name
  def pretty = { "My name is ${name}" }
  String toString(){
    pretty.call()
  }
}

Class Teacher{
  String name1 // 注意:與Student中的name變量名不同!!
}

def stu = new Studen(name: "Lqr")
def tea = new Teacher(name1: "Lxf")

// 一、Normal
println stu.toString()

// 二、優先委託delegate
stu.pertty.delegate = tea
stu.pertty.resolveStrategy = Closure.DELEGATE_FIRST
println stu.toString()

// 三、只委託delegate
stu.pertty.delegate = tea
stu.pertty.resolveStrategy = Closure.DELEGATE_ONLY
println stu.toString()
複製代碼

輸出:

// 一、Normal
My name is Lqr

// 二、優先委託delegate
My name is Lqr // 若是Teacher中的name1改成name,則輸出變爲:My name is Lxf

// 三、只委託delegate
報錯:No Such property: name for class Teacher
複製代碼

groovy數據結構

1、列表

定義、操做(增刪查排)

// 列表的定義
def list = [1, 2, 3, 4, 5] // groovy中的列表就是ArrayList
println list.class
println list.size()
// 數組的定義
def array = [1, 2, 3, 4, 5] as int[] // 使用as int[]轉換
int[] array = [1, 2, 3, 4, 5] // 使用強類型定義

// ============= 列表的添加 =============
list.add(6)
list.leftShift(7)
list << 8
println list.toListString()
def plusList = list + 9
println plusList.toListString()

// ============= 列表的刪除 =============
list.remove(7)
list.remove((Object)7)
list.removeAt(7)
list.removeElement(6)
list.removeAll { return it % 2 == 0}
println list - [6, 7]
println list.toListString()
 
// ============= 列表的排序 =============
def sortList = [6 -3, 9, 2, -7, 1, 5]
sortList.sort() // java中:Collections.sort(sortList)
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 { it -> return it.size()}
println sortStringList

// ============= 列表的查找 =============
def findList = [-3, 9, 6, 2, -7, 1, 5]
// find() : 返回第一個符合條件的元素
int result = findList.find { return it % 2 == 0}
println result
// findAll() : 返回全部符合條件的元素
def resultfindList.findAll{ return it % 2 != 0}
println result.toListString()
// any() : 若列表中有一個知足條件就返回true
def result = findList.any { return it % 2 != 0} 
println result
// every() : 列表中全部元素都知足條件才返回true
def result = findList.every {return it % 2 != 0}
println result
// min() : 返回最小值
println findList.min() // findList.min { return Math.abs(it) } 查找最小絕對值
// max() : 返回最大值
println findList.max() // findList.max { return Math.abs(it) } 查找最大絕對值
// count() : 統計符合條件的元素個數
def num = findList.count { return it % 2 == 0}
println num
複製代碼

輸出

// 列表的定義
class java.util.ArrayList
5

// ============= 列表的排序 =============
[-7, -3, 1, 2, 5, 6, 9]
// 自定義排序規則:按絕對值反方向排序
[9, -7, 6, 5, -3, 2, 1]
// 自定義排序規則:按字符串長度排序
['z', 'abc', 'java', 'Hello', 'groovy']

// ============= 列表的查找 =============
// find
6
// findAll() 
[-3, 9, -7, 1, 5]
// any() 
true
// every() 
false
// min()
1
// max() 
9
// count() 
2
複製代碼

2、映射

// 定義
def colors = [
  red : 'ff0000',
  green : '00ff00',
  blue : '0000ff'
]
println colors.getClass() // 注:不能直接使用colors.class,由於這樣會查找key爲class的元素
// 強行指定類型:def colors = [...] as HashMap 或 HashMap colors = [...]

// 索引方式
println colors['red']
println colors.red
println colors.blue
// 添加元素
colors.yellow = 'ffff00'    // 添加同類型key-value
colors.complex = [a:1, b:2] // 添加任意類型key-value
println colors.toMapString()
// 刪除元素
colors.remove(red)

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']
]

// 遍歷
students.each { def student -> 
  println "the key is ${student.key}, "+
    "the value is ${student.value}"
}
// 帶索引遍歷
students.eachWithIndex { def student, int index ->
  println "the index is ${index}, "+
    "the key is ${student.key}, "+
    "the value is ${student.value}"
}
// 直接遍歷key-value
students.each { key, value -> ...}
students.eachWithIndex { key, value, index -> ...}

// 查找
def entry = students.find { def student ->
  return student.value.score >= 60
}
println entry
def entrys = students.findAll { def student ->
  return student.value.score >= 60
}
println entrys
// 統計及格男生個數
def count =  students.count { def student ->
  return student.value.score >= 60 && student.value.sex == 'male'
}
println count
// 過濾:獲取全部及格同窗的姓名
def names = students.findAll { def student ->
  return student.value.score >= 60
}.collect{ // 過濾出元素指定屬性列
  return it.value.name
}
println names.toListString()
// 分組:對及格與不及格學生進行分組
def group = students.groupBy {def student ->
  return student.value.score >= 60 ? '及格' : '不及格'
}
println group.toMapString()

// 排序
def sort = students.sore { def student1, def students ->
  Number score1 = student1.value.score
  Number score2 = student2.value.score
  return score1 == score2 ? 0 : score1 < score2 ? -1 : 1
}
println sort
複製代碼
// 定義
class java.util.LinkedHashMap

// 索引方式
ff0000
ff0000
0000ff
// 添加元素
[red:ff0000, green:00ff00, blue:0000ff, yellow:ffff00, complex:[a:1, b:2]]

// 遍歷
the key is 1, thie value is [number:0001, name:Bob, score:55, sex:male]
the key is 2, thie value is [number:0002, name:Johnny, score:62, sex:female]
the key is 3, thie value is [number:0003, name:Claire, score:73, sex:female]
the key is 4, thie value is [number:0004, name:Amy, score:66, sex:male]
// 帶索引遍歷
the index is 0, the key is 1, thie value is [number:0001, name:Bob, score:55, sex:male]
the index is 1, the key is 2, thie value is [number:0002, name:Jhonny, score:62, sex:female]
the index is 2, the key is 3, thie value is [number:0003, name:Claire, score:73, sex:female]
the index is 3, the key is 4, thie value is [number:0004, name:Amy, score:66, sex:male]

// 查找
// find
2={number=0002, name=Johnny, score=62, sex=female}
// findAll
[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]]]
// count
1
// collect
[Johnny, Claire, Amy]
// groupBy
[不及格:[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]]]]

// 排序
[1:[number:0001, name:Bob, score:55, sex:male], 2:[number:0002, name:Johnny, score:62, sex:female], 4:[number:0004, name:Amy, score:66, sex:male]], 3:[number:0003, name:Claire, score:73, sex:female]]
複製代碼

其餘:

  • map定義時,key一般是用不可變字符串或number來定義。
  • 字符串不使用單引號時,groovy默認會認爲是不可變的單引號字符串。(如:red 與 'red' 同樣)

3、範圍

Range定義、操做(each、switch-case)

def range = 1..10           // Range是一個繼承於List的接口,即,本質是列表
println range[0]            // 範圍第一個數值
println range.contains(10)  // 範圍是否包含10
println range.from          // 範圍中第一個值
println range.to            // 範圍中最後一個值

// 遍歷
range.each {
  println it
}
for(i in range){
  println i
}

// switch-case
def getGrade(Number number){
  def result
  switch(number){
    case 0..<60: // [0, 60)
      result = '不及格'
      break;
    case 60..<70:
      result = '及格'
      break;
    case 70..<80:
      result = '良好'
      break;
    case 80..100: // [80, 100]
      result = '優秀'
      break;
  }
  result // 至關於 return result。此處能夠省略return,groovy中方法會默認返回最後一行的結果
}

複製代碼

groovy面向對象

1、類、接口等的定義和使用

// 類的定義
class Person{
  String name
  
  Integer age // int與Integer是同樣的,groovy中,int本質就是Integer
  
  def increaseAge(Integer years){
    this.name += years
  }
}

// 建立對象
def person = new Person(name: 'Lqr', age: 18) // 也能夠只直接一部分,如:new Person(name: 'lqr')或不指定
println "the name is ${person.name}, the age is ${person.age}"
person.increaseAge(10)

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

// trait類定義(與java中的抽象類差很少)
trait DefaultAction {
  abstract void eat()
  void play(){
    println ' i can play.'
  }
}
複製代碼

結論

  • groovy中默認都是public(類、成員屬性、方法等)
  • groovy類繼承自groovy.lang.GroovyObject(而java類則繼承自Object)
  • def定義的方法,其返回值就是Object
  • groovy類會默認會成員變量生成getter與setter方法。
  • 不管你是直接.仍是調用get/set,最終都是調用get/set方法,如:person.name至關於person.getName()
  • groovy接口中不容許定義非public的方法(如:protected void eat()是不行的)

2、元編程

groovy運行時類方法調用流程:

在java中,若是對象調用了一個類中沒有定義過的方法時,連編譯都編譯不過,可是在groovy中,狀況則不一樣(能夠編譯經過),根據圖中流程能夠知道,運行期間,當對象調用了一個類中沒有的方法時,會依次調用metaClass中的同名方法,類中的methodMissing(String name, Object args)方法,類中的invokeMethod(String name, Object args)方法,執行到其中一個便中止後續方法查找調用。

一、定義invokeMethod

當只定義類的invokeMethod(String name, Object args)方法時,運行時調用對象一個不存在的方法時,會執行invokeMethod()。

class Person{
  ...
  // 一個方法找不到時,調用它代替
  def invokeMethod(String name, Object args){
    return "the method is ${name}, the params is ${args}"
  }
}

def person = new Person(name: 'Lqr', age: 18)
person.cry()
複製代碼

輸出:

the method is cry, the params is []
複製代碼

二、定義methodMissing

當同時定義了類中的invokeMethod()、methodMissing()方法時,優先執行methodMissing(String name, Object args)

class Person{
  ...
  // 一個方法找不到時,調用它代替
  def invokeMethod(String name, Object args){
    return "the method is ${name}, the params is ${args}"
  }
  
  def methodMissing(String name, Object args){
    return "the method ${name} is missing"
  }
}

def person = new Person(name: 'Lqr', age: 18)
person.cry()
複製代碼

輸出:

the method cry is missing
複製代碼

三、metaClass

metaClass即是groovy中的元編程核心。在groovy中,可使用metaClass爲類在運行時動態添加 屬性 和 方法

用處:對第三方庫中的final類進行擴展。

// 爲類動態添加一個屬性
Person.metaClass.sex = 'male' // 同時設置動態屬性sex的默認值爲male
def Person = new Person(name: 'Lqr', age: 18)
println person.sex
person.sex = 'female'
println "the new sex is:" + person.sex

// 爲類動態添加方法
Person.metaClass.sexUpperCase = { -> sex.toUpperCase() }
def person2 = new Person(name: 'Lqr', age: 18)
println person2.sexUpperCase()

// 爲類動態添加靜態方法
Person.metaClass.static.createPerson = {
  String name, int age -> new Person(name: name, age: age)
}
def person3 = Person.createPerson('Lqr', 18)
println person3.name + ' and ' + person.age
複製代碼

輸出:

// 爲類動態添加一個屬性
male
the new sex is:female
// 爲類動態添加方法
MALE
// 爲類動態添加靜態方法
Lqr and 18
複製代碼

以上能夠看到groovy的metaClass功能十分強大,但它自己有一個限制須要咱們注意一下,即:默認狀況下metaClass注入的屬性與方法只是短暫的(準確來講是非全局的)。

舉個例子在ClassA中對Person進行了metaClass擴展並正常調用動態注入的屬性和方法,可是在ClassB中,若也要使用前面動態注入的屬性和方法是不行的,由於在groovy中metaClass動態注入的屬性和方法默認是非全局的,你能夠有以下2種作法:

  1. 在ClassB中再使用metaClass再動態注入一次屬性和方法。
  2. 使用ExpandoMetaClass.enableGlobally()。

四、ExpandoMetaClass.enableGlobally()

使用ExpandoMetaClass.enableGlobally()開啓metaClass動態全局注入 屬性、方法 功能。

// 在ApplicationManager調用ExpandoMetaClass.enableGlobally(),並對Person進行擴展
class ApplicationManager{
  static void init(){
    ExpandoMetaClass.enableGlobally()
    // 爲第三方類添加方法
    Person.metaClass.static.createPerson = { String name, int age ->
      new Person(name: name, age: age)
    }
  }
}

// 在ClassB中可使用Person動態注入的擴展方法了
class ClassB{
  def test(){
    def person = Person.createPerson('Lqr', 18) // 由於只是普通方法,不是構造函數,因此不能這樣:createPerson(name: 'Lqr', age: 18) ,切記!!
    println "the person name is ${person.name} and the age is ${person.age}"
  }
}

// Entry模擬一個App的運行入口
class Entry{
  static void main(String[] args){
    ApplicationManager.init()
    new ClassB().test()
  }
}
複製代碼

輸出:

the person name is Lqr and the age is 18
複製代碼
相關文章
相關標籤/搜索