如何创建一个 groovy 项目?
使用 idea 按照下图的选项创建一个新项目:
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)