语言特性
Groovy
注释标记和 Java 一样,支持 // 或者 /**/Groovy
语句可以不用分号结尾。 (Groovy
为了尽量减少代码的输入,确实煞费苦心)Groovy
中支持动态类型,即定义变量的时候可以不指定其类型。Groovy
中,变量定义可以使用关键字def
。 注意,虽然def
不是必须的,但是为了代码清晰,建议还是使用def
关键字
def varInstanceOfInteger = 1
def varInstanceOfString = "This line has no meanings."
def int integer1 = 2 //也可以直接指定类型
4.函数定义时参数可以不指定类型(理解成java里参数赛泛型即可)
String function(arg1,arg2){
...
}
5.除了上面的几点外, 函数的返回值也可以是无类型的;(不过因为Groovy
是基于Java
并最后运行在JVM
上, 这些所谓的无返回值的函数应该都是用的Object
类型吧)
就比如:
def function1(){
// (这最后一行代码即是该函数的返回值)
}
String function(){
return "This is a string."
//如果指定了函数的返回类型, 则可不必加def关键字来定义函数
}
6.函数返回值: Groovy的函数里, 可以不适用 return关键字. 如果不使用的话, 则函数里最后一句代码的执行结果被设置成返回值.
def function(){
"something"//如果是最后一行,输出"something"
1 //如果是最后一行,输出 1
//按我目前这样的写法 1 为最后一行,所以输出1
}
如果在定义函数的时候声明了返回值类型的话, 函数中则必须使用正确的数据类型, 否则运行时会报错. 如果没声明类型即可随便返回.
7.String
和Gstring
那么在Java
中使用的是String
, 那么在兼容的groovy
里当然也可以使用String
, 不过groovy
也提供的有Gstring
供我们使用.
三个引号( ‘’’ )中的字符串更支持随意换行:
def sth = "This is Line 1"
//这就是String的写法
----------------------------------------
def num = 1
def sth2 = "This is Line $num"
//这种是Gstring的写法,
//和mybatis的传值有着异曲同工之妙
---------------------------------------
def multiPart = '''
第一行
第二行
第三行
第四行...
'''
8.Groovy
中调用函数时也可以不加括号, 比如:
print()
-> print
/ 两个效果是一样的
因为不加括号, 所以有时候Groovy
经常性的会把函数和属性的调用混淆.
如图就是
9.groovy
中的==
在一般情况下
java
中的==表示引用相同
但是在groovy
中如果对象实现了Comparable
, 那么就可以通过 .compareTo()==0
来表示是否相等.
如果对象没有实现Comparable
, 则会用 .equals()
来进行判断;
注: 在groovy
中如果要判断两个对象引用是否相等则使用 .is()
10.assert
就相当于一种trycatch
或者fail-fast
这种机制, 如果assert判断的代码不为true
, 则直接停止运行并报错, 后面的就不会再执行, 如果为true
则接着执行后面的代码.
API docs
http://docs.groovy-lang.org/docs/latest/html/api/index.html
这个是groovy
的官方api文档, 有不会的类或者不明白具体实现的即可在这上面进行查找.
List操作
其实就还是Java
里的那套东西
List迭代
因为许多内容与Java中的重复, 所以下面我就只说相对特殊一点的.
区间(Ranges)
Ranges定义使用 … 代表闭区间(包括起点和终点)
Ranges定义使用 …< 代表一个半开半闭,只包含第一个值不包含最后一个值。
def range = 1..10
range.size() //==10
range.get(2) //==3
range.contains(1) //==true
range instanceof java.util.List //true
//以上是闭区间
//以下是半开区间
def range 1..<10
range.size() //==9
range.get(2) //3
range.contains(10) //==false
//不用下标的方式
range.from == 1
range.to == 10
当然这样的操作在关于字母也是一样
def range = 'a'..'d'
assert range.size() //==4
assert range.size() //== 4
assert range.get(2) //== 'c'
assert range[2] //== 'c'
assert range instanceof java.util.List //==true
assert range.contains('a') //==true
assert range.contains('d') //==true
assert range.contains('e') //==false
这样便捷的操作在操作for循环也是可以的
for(i in 1..10){
println "输出第${i}次"
}
//Groovy的风格是
(1..10).each{i ->
println "输出第${i}次"
}
在switch语句中也可以存在, 用于判断年龄等非常好用
switch(years){
case 10..17: println "青少年";
break;
case 18..60: println "成年人";
break;
case 61..100: println "老年人";
break;
}
GPath支持
def listOfMaps = [
['a': 11, 'b': 12],
['a': 21, 'b': 22]
]
assert listOfMaps.a //== [11,21]
assert listOfMaps*.a == [11, 21]
listOfMaps = [['a': 11, ‘b': 12], [‘a': 21, 'b': 22], null]
assert listOfMaps*.a == [11, 21, null]
assert listOfMaps*.a == listOfMaps.collect { it?.a }
*号操作
简单来说, 星号操作是允许你在一个集合的全部元素中调用某个方法或属性的简洁操作:
assert [1, 3, 5] //== ['a', 'few', 'words']*.size()
class Person {
String name
int age
}
def persons = [
new Person(name:'Hugo', age:17),
new Person(name:'Sandra',age:19)
]
assert [17, 19] //== persons*.age
使用下标操作
可以使用下标来索引lists, arrays, maps.
def text = 'nice cheese gromit!'
def x = text[2]
assert x //== 'c'
assert x.class == String
def sub = text[5..10]
assert sub //== 'cheese'
def list = [10, 11, 12, 13]
def answer = list[2,3]
assert answer //== [12,13]
也可以使用区间来提取集合:
list = 100..200
sub = list[1, 3, 20..25, 33]
assert sub
//== [101, 103, 120, 121, 122, 123, 124, 125, 133]
对于不可变的集合来说, 下标操作也可以用于更新已有集合
list = ['a','x','x','d']
list[1..2] = ['b','c']
assert list //== ['a','b','c','d']
比较令人眼前一亮的是, 在下标操作这块, 负数也是被允许的, 表示从集合后面提取元素, 比如:
text = "nice cheese gromit!"
x = text[-1]
assert x //== "!"
def name = text[-7..-2]
assert name //== “gromit”
同样的, 如果倒着使用区间(起点大于终点这种), 结果也会是反的
text = "nice cheese gromit!"
name = text[3..1]
assert name //== "eci"
Expando
Expando
类可以用于动态创建可拓展对象。尽管它的类名没有采用ExpandoMetaClass
。每一个Expando
对象代表一个独立的动态的实例,可以在运行时被属性或方法所拓展
def expando = new Expando()
expando.name = 'John'
assert expando.name //== 'John'
一个特殊的例子是当一个动态属性注册到一个闭包代码块。一个注册就可以被方法所动态调用:
def expando = new Expando()
expando.toString = { -> 'John' }
expando.say = { String s -> "John says: ${s}" }
assert expando as String //== 'John'
assert expando.say('Hi') //== 'John says: Hi'
可观察的list,map和set
Groovy提供了可观察的lists,maps和sets。每一个都是一个 java.beans.propertyChangeEvnent事件的触发器。当元素被添加,删除,修改就会被触发。注意 PropertyChangeEvent不仅仅当某些事件发生才出发,同时可以保存新旧值。
可能会有类型改变,可观察的集合可能需要更加特别的PropertyChangeEvnet类型。比如当添加一个元素到可观察list触发一个ObservableList.ElementAddedEvent事件。
def event //(1)
def listener = {
if (it instanceof ObservableList.ElementEvent) { //(2)
event = it
}
} as PropertyChangeListener
def observable = [1, 2, 3] as ObservableList //(3)
observable.addPropertyChangeListener(listener) //(4)
observable.add 42 //(5)
assert event instanceof ObservableList.ElementAddedEvent
def elementAddedEvent = event as ObservableList.ElementAddedEvent
assert elementAddedEvent.changeType == ObservableList.ChangeType.ADDED
assert elementAddedEvent.index == 3
assert elementAddedEvent.oldValue == null
assert elementAddedEvent.newValue == 42
(1)声明一个PropertyChangeEventListener可以捕捉触发事件
(2)ObservableList.ElementEvent和它的相关类型是相对与这个监听器
(3)注册一个监听器
(4)从给定的list创建一个ObservableList
(5)ObservableList.ElementAddedEvent事件的触发器
注意,添加一个元素将会触发两个事件,第一个是ObservableList.ElementAddedEvent 第二个是 PropertyChangeEvent,用来通知监听器这次修改属性的size
ObservableList.ElementClearedEvent 事件类型是另外一个有趣的事件。无论什么时候多个元素被删除,比如当我们调用clear()方法的时候,它将会保存被删除的元素
def event
def listener = {
if (it instanceof ObservableList.ElementEvent) {
event = it
}
} as PropertyChangeListener
def observable = [1, 2, 3] as ObservableListobservable.addPropertyChangeListener(listener)
observable.clear()
assert event instanceof ObservableList.ElementClearedEvent
def elementClearedEvent = event as ObservableList.ElementClearedEvent
assert elementClearedEvent.values //== [1, 2, 3]
assert observable.size() //== 0
在这块ObservableMap
和ObservableSet
是相似的同一个概念,和ObservableList
一样.
那么以上就是Groovy
的基础以及部分语法.
如果想要有更好的理解, 建议翻阅官方的api文档, 或者在开源社区https://www.open-open.com/lib/view/open1444055981994.html#articleHeader4查阅也可以, 我本人就参考了许多.