groovy基础语法
一、变量
1、类型
对象类型、基本类型(本质是对象类型)
int x = 0println x.classdouble y = 3.14println y.class
输出:
class java.lang.Integerclass java.lang.Double
结论:
从log输出可以得出,groovy中实质上是没有基本类型的,本质是java中的装箱对象类型。
2、定义
强类型定义方式、弱类型def定义方式
def x_1 = 11println x_1.classdef y_1 = 3.1415println y_1.classdef name = 'Android'println name.class
输出:
class java.lang.Integerclass java.math.BigDecimalclass java.lang.String
二、字符串
String、GString
1、常用的三种定义方式
// 单引号:与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" // Stringprintln doubleName.classdef doubleName1 = "Hello: ${name}" // GStringprintln doubleName1.class
// 单引号class java.lang.String// 三引号class java.lang.String line one line two line three// 双引号class java.lang.Stringclass org.codehaus.groovy.runtime.GStringImpl
2、新增操作符
方法来源: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()
输出:
// centeragroovya// padLefaagroovy// str > str2true// str[0]g// str[0..1]gr// str - str2ovy// reverseyvoorg// capitalizeGroovy// isNumberfalse
三、新增API讲解
逻辑控制:顺序逻辑(单步往下执行)、条件逻辑(if/else、switch/case)、循环逻辑(while、for)
// ============= 条件逻辑 =============def x = 1.23def resultswitch(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 }
输出:
// x = 1.23big decimal// x = 4list
groovy闭包讲解
一、基础
闭包概念(定义、调用)、闭包参数(普通参数、隐式参数)、闭包返回值(总是有返回值的)
// ============= 闭包概念 =============// 定义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, groovydef result = clouser() println resultdef clouser = {println 'Hello groovy!'} // 返回 nulldef result = clouser() println result
二、使用
闭包的用法:与基本类型的结合使用、与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循环到numberint 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:遍历每个字符,只要满足条件就返回truedef result= str.any { String s -> s.isNumber() } println result// every:遍历每个字符,所有都要满足条件才会返回trueprintln str.every { String s -> s.isNumber }// collect:遍历每个字符,经过闭包处理后,添加进list中返回def list = str.collect { it.toUpperCase() } println list.toListString()// ============= 与数据结构结合使用 =============// ============= 与文件等结合使用 =============// 后续篇章中会涉及
输出:
// ============= 与String结合使用包参数 =============// eachthe 2 and 3 is 5// find2// final All[2, 3, 5]// anytrue// everyfalse// collect[T, H, E, , 2, , A, N, D, , 3, , I, S, , 5]
三、进阶
闭包关键变量(this、owner、delegate)
// this == owner == delegatedef scriptClosure = { println "scriptClosure this:"+this // 代表闭包定义处的类 println "scriptClosure owner:"+owner // 代表闭包定义处的类或者对象 println "scriptClosure delegate:"+delegate // 代码任意对象,默认与owner一致} scriptClosure.call()// this != owner == delegatedef nestClosure = { def innerClosure = { prinln "innerClosure this:"+this prinln "innerClosure owner:"+owner prinln "innerClosure delegate:"+delegate } innerClosure.call() }// this != owner != delegatedef nestClosure = { def innerClosure = { prinln "innerClosure this:"+this prinln "innerClosure owner:"+owner prinln "innerClosure delegate:"+delegate } innerClosure.delegate = new Person() // 手动修改delegate的值 innerClosure.call() }
输出
// this == owner == delegatescriptClosure this:variable.closurestudy@2ef3eef9 scriptClosure owner:variable.closurestudy@2ef3eef9 scriptClosure delegate:variable.closurestudy@2ef3eef9// this != owner == delegateinnerClosure this:variable.closurestudy@2ef3eef9 innerClosure owner:variable.closurestudy$_run_closure2@402bba4f innerClosure delegate:variable.closurestudy$_run_closure2@402bba4f// this != owner != delegateinnerClosure 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")// 1、Normalprintln stu.toString()// 2、优先委托delegatestu.pertty.delegate = tea stu.pertty.resolveStrategy = Closure.DELEGATE_FIRST println stu.toString()// 3、只委托delegatestu.pertty.delegate = tea stu.pertty.resolveStrategy = Closure.DELEGATE_ONLY println stu.toString()
输出:
// 1、NormalMy name is Lqr// 2、优先委托delegateMy name is Lqr // 如果Teacher中的name1改为name,则输出变为:My name is Lxf// 3、只委托delegate报错:No Such property: name for class Teacher
groovy数据结构
一、列表
定义、操作(增删查排)
// 列表的定义def list = [1, 2, 3, 4, 5] // groovy中的列表就是ArrayListprintln list.classprintln 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 << 8println list.toListString()def plusList = list + 9println 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() : 若列表中有一个满足条件就返回truedef result = findList.any { return it % 2 != 0} println result// every() : 列表中所有元素都满足条件才返回truedef 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.ArrayList5 // ============= 列表的排序 ============= [-7, -3, 1, 2, 5, 6, 9]// 自定义排序规则:按绝对值反方向排序[9, -7, 6, 5, -3, 2, 1]// 自定义排序规则:按字符串长度排序['z', 'abc', 'java', 'Hello', 'groovy']// ============= 列表的查找 =============// find6// findAll() [-3, 9, -7, 1, 5]// any() true// every() false// min()1// max() 9// count() 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-valuecolors.complex = [a:1, b:2] // 添加任意类型key-valueprintln 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-valuestudents.each { key, value -> ...} students.eachWithIndex { key, value, index -> ...}// 查找def entry = students.find { def student -> return student.value.score >= 60} println entrydef 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// 索引方式ff0000ff00000000ff// 添加元素 [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]// 查找// find2={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]]]// count1// 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' 一样)
三、范围
Range定义、操作(each、switch-case)
def range = 1..10 // Range是一个继承于List的接口,即,本质是列表println range[0] // 范围第一个数值println range.contains(10) // 范围是否包含10println range.from // 范围中第一个值println range.to // 范围中最后一个值// 遍历range.each { println it }for(i in range){ println i }// switch-casedef 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面向对象
一、类、接口等的定义和使用
// 类的定义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()是不行的)
二、元编程
groovy运行时类方法调用流程:
在java中,如果对象调用了一个类中没有定义过的方法时,连编译都编译不过,但是在groovy中,情况则不同(可以编译通过),根据图中流程可以知道,运行期间,当对象调用了一个类中没有的方法时,会依次调用metaClass中的同名方法,类中的methodMissing(String name, Object args)方法,类中的invokeMethod(String name, Object args)方法,执行到其中一个便停止后续方法查找调用。
1、定义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 []
2、定义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
3、metaClass
metaClass便是groovy中的元编程核心。在groovy中,可以使用metaClass为类在运行时动态添加 属性 和 方法
用处:对第三方库中的final类进行扩展。
// 为类动态添加一个属性Person.metaClass.sex = 'male' // 同时设置动态属性sex的默认值为maledef 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种做法:
在ClassB中再使用metaClass再动态注入一次属性和方法。
使用ExpandoMetaClass.enableGlobally()。
4、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
作者:GitLqr
链接:https://www.jianshu.com/p/dbbd24591104
共同学习,写下你的评论
评论加载中...
作者其他优质文章