Groovy不了解一下吗?
最近听说用Groovy写单元测试很爽,来凑个热闹,尽可能短,尽可能少,没明说的就当Java来写就好。
国际惯例Hello World
关于Groovy的东西就不鬼扯了,反正就是一个基于JVM的没火起来的语言,进入正题
class GroovyTut {
static void main(String[] args)
println("Hello Groovy!") // 可以没有分号!
}
}
其实,还可以这样:
print("Hello Groovy!")
但由于Groovy本质是基于JVM的,所以最终这行代码还是会被包裹在一个自动生成的类里面。
一些有必要知道的特性
- 默认访问修饰符是public
- groovy根据实参类型选择方法(动态分派),Java则根据声明类型,两者恰恰相反
- groovy的
==
可以看作是Java的equals
变量
def a = "test" //自动推导变量类型
int b = 32 // 也可以像Java一样定义变量
跟很多动态语言很类似,至于其确切类型的种类,嗯,就是你想的那样,和Java类型基本一样。
字符串
def a = 'test' // String类型
def b = "插值字符串:${a}"
def c = "还可以插入表达式:${1+3+4}"
def d = "甚至还可以插入语句:${def a = 1; def b = 2; a + b}" // 一般不建议玩这么花
println(b) // 插值字符串:test
char d = 'd' // 至于真正的字符类型要显式声明或者强转
不得不说,这个特性贼有模板语言既视感。
单引号表示普通字符串,插值字符串要用双引号。
方法
String func(){
return "test"
}
assert func() == "test"
def func2(){
"test" // 返回最后一条语句结果
}
assert func2() == "test"
返回类型可以用 def 代替(可以把def看作类型的占位符),返回值 return 可以省略。
def add(a, b){
a + b
}
参数类型也可以被省略,默认为 Object 类型
在Java里,两个Object类型相加也是不容许的,但在Groovy里可以,因为如果传入字符串类型或者算术类型,这个操作显然合理,但是Java则会自始自终把参数当成Object来看,多得不说了,懂得都懂。
这也是Groovy一种动态性的体现,简单来说也就是程序不跑起来都不知道你是对是错。
闭包
我也不知道为什么叫闭包,在我的理解里闭包是一种机制也是一种操作,但Groovy里所谓的闭包(closure)其实更像是一个函数对象,而事实上它也确实是groovy.lang.Closure
类的实例
闭包语法如下,与Java8的lambda非常类似:
//闭包的参数为可选项
def closure = { [closureParameters -> ] statements }
def closure = { println("test") } //没参数可以省略 ->
def closure1 = { int a, int b -> a + b} //多个参数
def closure2 = { println(it) } //只有一个参数可省略,Groovy提供隐式参数it
调用闭包:
def closure = {
param -> println param
}
closure('hello') //直接把闭包变量当方法
closure.call('hello') //把闭包变量当实例对象
closure 'hello' // 当成关键字
这个机制(语法糖)还是很给力的。
List
def numbers = [1, 2, 3]
其实就是ArrayList
,不过这么定义真让我找到一丝Python的爽感。
Array
语法和List类似,不过要指定数组类型
String[] arrStr = ['Ananas', 'Banana', 'Kiwi'] //直接声明类型为数组类型 String[]
assert arrStr instanceof String[]
assert !(arrStr instanceof List)
def numArr = [1, 2, 3] as int[] //痛过as关键字指定类型为数组类型 int[]
assert numArr instanceof int[]
assert numArr.size() == 3
Map
/ key虽然没有加引号,不过Groovy会默认将其转换为字符串
def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']
assert colors['red'] == '#FF0000' // 使用中括号访问
assert colors.green == '#00FF00' // 使用点表达式访问
colors['pink'] = '#FF00FF' // 使用中括号添加元素,相当于Java Map 的 put(key,value)方法
colors.yellow = '#FFFF00'// 使用点表达式添加元素
assert colors.pink == '#FF00FF'
assert colors['yellow'] == '#FFFF00'
assert colors instanceof java.util.LinkedHashMap // 默认使用LinkedHashMap类型
// Groovy Map的key默认语法不支持变量,这里的key实际上是字符串'keyVal'而不是keyVal变量的值'name'
def keyVal = 'name'
def persons = [keyVal: 'Guillaume']
assert !persons.containsKey('name')
assert persons.containsKey('keyVal')
//要使用变量作为key,需要使用括号
def keyVal = 'name'
def persons = [(keyVal): 'Guillaume']
assert persons.containsKey('name')
assert !persons.containsKey('keyVal')
Groovy中的Map其实就是java.util.LinkedHashMap
。
Range
在 Groovy 中可以使用..
操作符来定义一个区间对象,简化范围操作的代码。
def range = 0..5
assert (0..5).collect() == [0, 1, 2, 3, 4, 5]
assert (0..<5).collect() == [0, 1, 2, 3, 4] // 相当于左闭右开区间
assert (0..5) instanceof List // Range实际上是List接口的实现
assert (0..5).size() == 6
assert ('a'..'d').collect() == ['a','b','c','d']//也可以是字符类型
//常见使用场景
for (x in 1..10) {
println x
}
('a'..'z').each {
println it
}
def age = 25;
switch (age) {
case 0..17:
println '未成年'
break
case 18..30:
println '青年'
break
case 31..50:
println '中年'
break
default:
println '老年'
}
说实话,switch这么玩我看傻了
命名参数
class PersonWOConstructor {
String name
Integer age
}
def person4 = new PersonWOConstructor()
def person5 = new PersonWOConstructor(name: 'Marie')
def person6 = new PersonWOConstructor(age: 1)
def person7 = new PersonWOConstructor(name: 'Marie', age: 2)
可以不定义构造器,如果要使用位置参数则要定义对应构造器。
Spread运算符*
可用于集合对象,相当于对每一个元素操作并将结果收集为一个List。
class Person{
String name;
Integer age;
}
def persons = [
new Person(name : "Kevin", age : 20),
new Person(name : "bob", age : 30),
]
def names= persons*.name
println(names) //[Kevin, bob]
这玩意还能用在任何实现了Iterable
接口的类对象上:
class Component {
Long id
String name
}
class CompositeObject implements Iterable<Component> {
def components = [
new Component(id: 1, name: 'Foo'),
new Component(id: 2, name: 'Bar')]
@Override
Iterator<Component> iterator() {
components.iterator()
}
}
def composite = new CompositeObject()
assert composite*.id == [1,2]
assert composite*.name == ['Foo','Bar']
还能用来传参:
def func(a, b, c){
a + b + c
}
def params = [1, 2, 3]
println(func(*params)) // 6
还能扩充List和Map
def items = [4,5]
def list = [1,2,3,*items,6]
assert list == [1,2,3,4,5,6]
def m1 = [c:3, d:4]
def map = [a:1, b:2, *:m1]
assert map == [a:1, b:2, c:3, d:4]
重载运算符!
class Person{
String name;
Person plus(obj){
return new Person(name:this.name + obj.name)
}
}
Person person=new Person(name : "kevin")
Person person1 =new Person(name : "test")
println((person + person1).name)
绝大多数的运算符都能重载,对应的函数名就不多费口舌了。