groovy 学习笔记
GROOVY 特殊点
默认导入
- java.lang
- java.util
- java.io
- java.net
- java.math.BigDecimal
- java.math.BigInteger
- groovy.lang
- groovy.util
轻量级Java
- Return 可选
- 分号分隔符可选
- 方法和类默认是public
- ?. 只分派不为null的对象
- 可以使用具名参数初始化javaBean
- 不需要捕获自己不关心的异常
- static方法也可以使用this来引用Class
GROOVY 语法
默认支持JAVA语法,所以所有
.groovy
文件中可以使用JAVA语法
循环
- range
for (i in 0..10) {
println i
}
- upto
0.upto(10) {
println it
}
it 是什么? upto方法接受一个闭包参数,如果闭包只需要一个参数,在groovy中可以使用默认的名字it来标示该参数, 切记用
- times
10.times {
print(it)
}
times 是默认从0开始,upto 是给定上限
- step
0.step(10, 2) {
print(it)
}
步长 0~10 步长2
安全导航操作
?.
def foo(str) {
str?.reverse()
}
println foo('hello')
str 不为null,则调用 str.reverse(), 这里包含了dolast未默认返回值的动作
异常处理
- 可以不显式catch异常, 自动向上抛
def openFile(fileName) {
new FileInputStream(fileName)
}
def openFile(fileName) {
try {
new FileInputStream(fileName)
} catch (ex) {
println(ex)
}
}
变量ex前面没有任何类型, 代表可以捕获任何异常, 但是注意: 不能捕获除Exception之外的Error或者Throuwable, 要捕获的话需要显示声明 catch (Trowable th)
javaBean
class Two {
def final name
private def address
Two(name) {
this.name = name
}
// void setAddress(newAddress) {
// throw new IllegalAccessException("error")
// }
}
def two = new Two('gc')
// two.name = 'gc2' 会抛异常
two.address = '222' //不会抛异常,如果需要限制, 需要重写 setAddress方法
println("$two.name")
println("$two.address")
灵活的初始化和具名参数
class Two {
def final name
private def address
def x, y, z
// void setAddress(newAddress) {
// throw new IllegalAccessException("error")
// }
}
// def two = new Two(name: 'gc', address: 'add', x: 1, y: 2, z: 3) 会报错,因为这个操作并不是构造器,所以会在构造器之后执行
def two = new Two(address: 'add', x: 1, y: 2, z: 3)
// two.name = 'gc2' 会抛异常
two.address = '222' //不会抛异常,如果需要限制, 需要重写 setAddress方法
println("$two.name")
println("$two.address")
println("$two.z")
println("$two.x")
println("$two.y")
def access(x, y, z) {
println "$x, $y, $z"
}
access(1, 2, 3)
access(x: 1, y: 2, z: 3, 50, true)
access(50, true, x: 1, y: 2, z: 3)
//1, 2, 3
////[x:1, y:2, z:3], 50, true
////[x:1, y:2, z:3], 50, true
如果groovy方法实参中存在map,则会自动将map传递给第一个形参, 如果要强制哪个参数为map, 可以
access(x, Map y, z)
这样写
可选形参
def access(x, y = 'y', z = 10) {
println "$x, $y, $z"
}
access(1)
access(1, 2)
access(1, 2, 3)
这里可选形参必须放在参数列表末尾, 方便在固有接口中增加参数,便于接口演进设计
def access(x, y = 'y', z = 10, String[] args) {
println "$x, $y, $z, $args"
}
access(1)
access(1, 2)
access(1, 2, 3)
access(1, 2, 3, '4', '5')
groovy 可以把参数最末尾的数组列表设置为可选的, 注意数组列表必须放在实参最末尾
多赋值
def access(str1, str2) {
[str1, str2] // 最后一句未默认返回, 这里必须返回数组
}
def (str1, str2) = access("gc1", "gc2") // 接受返回值的外面可以把数组拆开
def args1 = access("gc1", "gc2") // 也可以不拆开
println("$str1, $str2")
println("$args1")
//gc1, gc2
//[gc1, gc2]
这样交换变量就变得很方便
def access(str1, str2) {
[str2, str1]
}
def (str1, str2) = access("gc1", "gc2")
println("$str1, $str2")
//gc2 , gc1
如果左侧变量和右侧返回值数量一样,则一一映射,如果右面比左面多,则丢弃, 如果左面比右面多,则附null
如果左面的变量类型为基本类型,则附值为null的时候会抛异常 因为 int x = null 是非法的
实现接口
interface A {
void aOne(str)
void aTwo()
void aThree(str1, str2, str3)
}
def useA(A a) {
a.aOne("hello")
a.aTwo()
// a.aThree(1, 2, 3) // 将会异常, 因为在调用的时候无法区分it到底是哪个参数
}
useA({ println(it) } as A)
/**
hello
null
**/
groovy 并不强制实现接口中的所有方法,只需要实现自己关心的方法就行, 如果确定为未实现的方法永远不会被调用,则没有问题, 否则会有异常
interface A {
void aOne(str)
void aTwo()
}
def useA(A a) {
a.aOne("hello")
a.aTwo()
}
useA({
aOne:
{
println(it)
}
aTwo:
{
println("hello world")
}
} as A)
/**
hello
hello world"
**/
如果要实现的接口中由多个方法且实现姿势不一样,可以用
{methodName: {methodBody}, ....}
的姿势来实现
interface AI {
void methodOne()
}
interface AII {
void methodOne(str)
}
class B {
def useA(AI a) {
a.methodOne();
}
}
B b = new B()
def methodName = "useA"
def interfaceName = "AI"
b."$methodName"({ print("hello world") }.asType(Class.forName("$interfaceName"))) // 注意,这里不能使用 '$interfaceName' 单引号
上面的方法使用了动态的实现接口的方法
Bool求值
def bool1 = 1
def bool2 = "hello"
def bool3 = []
if (bool1) {
print(bool1)
}
if (bool2) {
print(bool2)
}
if (bool3) {
print(bool3)
}
groovy 不像java对bool值那么挑剔,以下表中列举了类型与布尔值的对应关系
类型 | 为真的条件 |
---|---|
Boolean | true |
Collection | 集合不为空 |
Character | 值不为0 |
CharSequence | 长度不为0 |
Iterator | hasNext为true |
Number | double不为0 |
Map | 不为空 |
Matcher | 至少有一个匹配 |
Object[] | 长度大于0 |
其他任何类型 | 引用不为null |
操作符重载
在groovy中,每一个操作符都映射到一个标准方法,这些方法在java中可以直接使用,在groovy中即可以使用方法,也可以使用操作符