groovy语言简介
- 一种基于JVM的敏捷开发语言,作为编程语言可编译成java字节码,也可以作为脚本语言解释执行。
- 结合了Python、Ruby和Smalltalk的许多强大的特性
- 支持面向对象编程也支持面向过程编程
- 支持动态类型,闭包等语言特性
- 无缝集成所有已经存在的java类库
groovy环境搭建
参考官网groovy环境搭建
groovy的hello world
在groovy语言中,如下两种写法效果完全相同
版本1:
class HelloGroovy {
public static void main(String[] args) {
System.out.println("hello groovy!");
}
}
版本2:
版本2看起来是脚本,其实是编译器帮我们变成了class,版本2脚本对应的class反编译为如下代码:
import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;
public class HelloGroovy extends Script {
public HelloGroovy() {
}
public HelloGroovy(Binding context) {
super(context);
}
public static void main(String... args) {
InvokerHelper.class.invoke<invokedynamic>(InvokerHelper.class, HelloGroovy.class, args);
}
public Object run() {
return this.invoke<invokedynamic>(this, "hello groovy");
}
}
我们直观感受一个是编译语言,一个是脚本语言,但其实最后都是编译执行的。
groovy基础语法
变量
变量类型:全部为对象类型,不存在基本类型,基本类型的定义都会被转化为对象类型。
package variable
int x = 10
println x.class
double y = 3.14
println y.class
输出为:
class java.lang.Integer
class java.lang.Double
变量定义:强类型和弱类型def定义
def x_1 = 3.1415
println x_1.class
def
定义时,会根据值的类型将变量转化为对应类型,重新赋值为其他数据类型的值,则变量类型也会变为其他数据类型
建议:内部使用的变量建议使用def
定义,而提供给外部程序使用的变量,则建议使用强类型
字符串
String
和GString
字符串使用单引号、双引号和三个单引号定义都等同为String
,区别:
- 单引号没有格式,格式需要转义,比如换行需要拼接;三个单引号可以直接指定格式
- 单引号不能引入扩展表达式,双引号可以在字符串中引入扩展表达式。如果双引号存在扩展表达式,类型则为
GString
//def name = 'a single \'a\'string'
//println name.class
def thupleName = '''line one
line two
line three
'''
//println thupleName
def doubleName = "this a common String"
//println doubleName.class
def name = "Qndroid"
def sayHello = "Hello: ${name}"
//println sayHello
//println sayHello.class
def sum = "the sum of 2 and 3 equals ${2 + 3}" //可扩展做任意的表达式
//println sum
String方法来源:
java.lang.String
,常用java类型,比较熟悉了
DefaultGroovyMethods
,groovy所有类型都有的方法
StringGroovyMethods
,继承DefaultGroovyMethods
,有普通类型的参数和闭包类型的参数
package org.codehaus.groovy.runtime;
...
public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
...
groovy新增的部分string方法如下:
/* ==================字符串的方法=================== */
def str = "groovy Hello"
//println str.center(8)
//println str.padLeft(8, 'a')
def str2 = 'Hello'
//println str > str2
//println str[0]
//println str[0..1]
//println str - str2
//println str.reverse()
//println str.capitalize()
逻辑控制
//对范围的for循环
def sum = 0
for (i in 0..9) {
sum += i
}
//println sum
sum = 0
/**
* 对List的循环
*/
for (i in [1, 2, 3, 4, 5, 6, 7, 8, 9]) {
sum += i
}
/**
* 对Map进行循环
*/
for (i in ['lili': 1, 'luck': 2, 'xiaoming': 3]) {
sum += i.value
}
方法调用
方法如果只有一个参数,可以省略()
groovy闭包
闭包定义、调用和返回值
闭包就是一段代码块,代码块用{ }
表示
def clouser = { println "hello groovy!" }
//闭包调用
//clouser.call()
clouser()
闭包普通参数和隐式参数
->之前就是参数部分,可以为空(没有参数)
//普通参数
def clouser = { String name -> println "hello ${name}!" }
//闭包调用
//clouser.call()def name = 'groovy!'
clouser(name)
//多个参数
def clouser = {String name, int age ->
println "hello ${name}, My age is ${age}"
}
def name = 'groovy!'
clouser(name,4)
//默认隐式参数 it
def clouser = { println "hello ${it}"}
def name = 'groovy!'
clouser(name)
闭包的返回值
如果有return
语句,则返回对应值,如果没有return
语句,则返回null
。
闭包的用法
与基本类型的结合,闭包参数需要查看源码,看需要传入的参数
int x = fab(5)
println x
//用来求指点number的阶乘
int fab(int number) {
int result = 1
1.upto(number, {num -> result *= num})
return result
}
//结果为120
int cal(int number) {
int result = 0
number.times {
num -> result += num
}
return result
}
upto
源码
public static void upto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) {
int self1 = self.intValue();
int to1 = to.intValue();
if (self1 <= to1) {
for (int i = self1; i <= to1; i++) {
closure.call(i);
}
} else
throw new GroovyRuntimeException("The argument (" + to +
") to upto() cannot be less than the value (" + self + ") it's called on.");
}
与String结合
String str = 'the 2 and 3 is 5'
//each的遍历,返回值为本身
str.each {
String temp -> print temp
}
//find 来查找符合条件的第一个
str.find {
String s-> s.isNumber()
}
find
源码
public static Object find(Object self, Closure closure) {
BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
Object value = iter.next();
if (bcw.call(value)) {
return value;
}
}
return null;
}
与数据结构结合
与文件等结合
闭包进阶
闭包关键变量this
闭包关键变量owner
闭包关键变量delegate
/**
* 闭包的三个重要变量:this,owner,delegate
*/
def scriptClouser = {
println "scriptClouser this:" + this //闭包定义处的类
println "scriptClouser owner:" + owner //闭包定义处的类或者对象
println "scriptClouser delegate:" + delegate //任意对象,默认为owner一致
}
scriptClouser.call()
//this为闭包定义处的类,
//定义了一个内部类,在脚本类中
class Person {
def static classClouser = {
println "classClouser this:" + this
println "classClouser owner:" + owner
println "classClouser delegate:" + delegate
}
def static say() {
def classClouser = {
println "methodClassClouser this:" + this
println "methodClassClouser owner:" + owner
println "methodClassClouser delegate:" + delegate
}
classClouser.call()
}
}
Person.classClouser.call()
Person.say()
//闭包中定义一个闭包
def nestClouser = {
def innerClouser = {
println "innerClouser this:" + this
println "innerClouser owner:" + owner
println "innerClouser delegate:" + delegate
}
innerClouser.call()
}
nestClouser.call()
闭包的委托策略
/**
* 闭包的委托策略
*/
class Student {
String name
def pretty = { "My name is ${name}"}
String toString() {
pretty.call()
}
}
class Teacher {
String name
}
def stu = new Student('Sarash')
def tea = new Teacher('Ondroid')
stu.pretty.delegate = tea
stu.pretty.resolveStrategy = Closure.DELEGATE_FIRST
println stu.toString()
常见数据结构使用
列表的定义
//def list = new ArrayList() //java的定义方式
def list = [1, 2, 3, 4, 5]
println list.class
println list.size()
def array = [1, 2, 3, 4, 5] as int[]
int[] array2 = [1, 2, 3, 4, 5]
列表的操作:原理为操作ArrayList
映射map
的定义
//def map = new HashMap()
def colors = [red : 'ff0000',
green: '00ff00',
blue : '0000ff']
//索引方式
//println colors['red']
//println colors.red
colors.blue
//添加元素
//colors.yellow = 'ffff00'
colors.complex = [a: 1, b: 2]
//println colors.getClass()
范围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 result = getGrade(75)
println result
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
}
return result
}
面向对象特性
类、接口等的定义和使用
类:
- groovy中默认都是public
- 无论你是直接还是调用get/set,最终都是调用get/set
接口:
接口中不许定义非public的方法
Trait:
和接口一样,唯一不同是可以有默认实现
元编程
方法寻找流程
- 类中是否有此方法
MetaClass
中是否有此方法
- 是否重写了
methodMissing()
- 是否重写了
InvokeMathod()
Throw MissingMethodException
为类动态的添加一个属性
Person.metaClass.sex = 'male'
为类动态的添加方法
Person.metaClass.nameUpperCase = { -> sex.toUpperCase()}
为类动态的添加静态方法
Person.metaClass.static.createPerson = {}
高级用法实战
json文件处理及json,model互转
代码样例:
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import objectorention.Person
//def json = JsonOutput.toJson(list)
def reponse =
getNetworkData(
'http://xxx.json')
println reponse.data.head.name
def getNetworkData(String url) {
//发送http请求---完全是使用java库
def connection = new URL(url).openConnection()
connection.setRequestMethod('GET')
connection.connect()
def response = connection.content.text
//将json转化为实体对象
def jsonSluper = new JsonSlurper()
return jsonSluper.parseText(response)
}
xml文件读取
代码样例:
import groovy.xml.MarkupBuilder
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>
'''
//开始解析此xml数据
def xmlSluper = new XmlSlurper()
def response = xmlSluper.parseText(xml)
//println response.value.books[0].book[0].title.text()
//println response.value.books[0].book[0].author.text()
//println response.value.books[1].book[0].@available
def list = []
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()
//深度遍历xml数据
def titles = response.depthFirst().findAll { book ->
return book.author.text() == '李刚' ? true : false
}
//println titles.toListString()
//广度遍历xml数据
def name = response.value.books.children().findAll { node ->
node.name() == 'book' && node.@id == '2'
}.collect { node ->
return node.title.text()
}
//println name
普通文件的读写
java文件处理
- 节点流:
InputStream
,OutputStream
及其子类
- 处理流:
Reader
,Writer
及其子类
所有java对文件的处理类,groovy都可以使用
groovy扩展了许多更加快捷和强大的方法
代码示范:
def file = new File(pathname:'../../test.txt')
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 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
}
groovy与java对比
- 没有java那么多的限制
- 对java的功能进行了极大的扩展
- 既可以编写应用,也可以编写脚本
语法上区别:
- Groovy 语句可以不用分号结尾
- 定义变量的时候可以不指定其类型、Groovy 中函数的返回值也可以是无类型的
- 最后一行代码的执行结果就是函数的返回值
- 如果指定了函数返回类型,则可不必加 def 关键字来定义函数
- Groovy中函数调用的时候还可以不加括号
- 闭包是一段代码,所以需要用花括号括起来
- -> 箭头前面是参数定义,箭头后面是代码
- Groovy 中,当函数的最后一个参数是闭包的话,可以省略圆括号或闭包放在后面
- 如果发送的实参的个数多于方法的形参个数,而且多出的实参是名值对,那么Groovy会假设方法的第一个形参是一个Map,然后将实参列表中的所有名值对组织到一起,作为第一个形参的值,之后,再将剩下的实参按照给出的顺序赋给其他的形参,就和我们输出的结果一样。