groovy学习笔记
groovy是一门类似于java的语言,在java语言的基础上,它吸收了很多脚本的特性,比如python,ruby。跟java一样,每个groovy文件也是编译成class文件,在JVM上运行。但是相比java,groovy的表达方式会更为简便。最近通过http://groovy.zeroleaf.com/core-syntax.html和http://docs.groovy-lang.org/next/html/documentation/来学习groovy。这2篇其实是差不多的,前一个是简单的中文版,是一些groovy的基础语法。后一个是英文原版。
我是一个IDE重度患者,所以选择使用IntelliJ来学习groovy。
环境配置
下载groovy库
$ curl -s http://get.sdkman.io | bash
使环境变量生效
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
安装 Groovy
$ sdk install groovy
此时可以查看groovy版本
192:~ fish$ groovy -v
Groovy Version: 2.4.7 JVM: 1.7.0_79 vendor: Oracle Corporation OS: Mac OS X
OK,groovy安装成功
配置IntelliJ
IntelliJ安装的时候默认就会装上groovy插件,我们只要配置下project sdk和groovy library就好了
1、把groovy库从.sdkman复制出来,放到另一个目录。我是把groovy文件夹从/Users/fish/.sdkman/candidates/拷贝到/Users/fish/Documents/。
(因为.sdkman是隐藏文件,所以选择groovy library的时候没办法点到,所以我才把它拷贝出来,这1步应该可以省略的,希望)
2、点击new project,在左边列表选择groovy,右边project sdk选择jdk 1.8,groovy Library点击Create,然后选择/Users/fish/Documents/groovy/2.4.7,结果如下所示
3、点击next 就可以了创建一个空的groovy工程了
4、在src下new->groovy script,创建一个groovy脚本,在里面输入
printf "aaa"
点击右键run就可以看到控制台上输出了aaa。
至此,groovy环境配置完成,以后就可以用IntelliJ来开发groovy工程了。
好了,可以开始groovy学习之旅了
标识符
普通标识符
标识符(identifiers)以字母,美元符号$ 或者下划线开始. 不能以数字开始,如下所示,注意定义一个变量要写def,不用写明变量类型,因为groovy是动态类型的语言。当然写明变量类型也可以,此时就不用写def了。
def name
def item3
def with_underscore
def $dollarstart
//定义了一个String
def sex="male"
//定义了一个Integer
def age=4
//定义了一个map
def map = [:]
引用标识符
引用标识符(quoted identifiers)位于点表达式(dotted expression)的点号之后.
//定义一个map
def map = [:]
map."an identifier with a_3_2 space and double quotes" = "ALLOWED"
map.'with-dash-signs-and-single-quotes' = "ALLOWED"
map.'a'='b'
assert map.'a'=='b'
assert map.a=='b'
//语法错误
//assert map.an identifier with a_3_2 space and double quotes == "ALLOWED"
assert map."an identifier with a_3_2 space and double quotes" == "ALLOWED"
assert map.'with-dash-signs-and-single-quotes' == "ALLOWED"
groovy 字符串
字符串形式
首先来看下groovy字符串的表现形式,字符串表示的形式多种多样,如下所示
def map = [:]
map.'dollar slashy string'="dollar"
//如下类型字符串作为引用标识符都是对的
map.'single quote'
map."double quote"
map.'''triple single quote'''
map."""triple double quote"""
map./slashy string/
assert map.$/dollar slashy string/$=="dollar"
//稍微特殊的GString,也是对的
def firstname = "Homer"
map."Simson-${firstname}" = "Homer Simson"
assert map.'Simson-Homer' == "Homer Simson"
Groovy有java.lang.String和groovy.lang.GString两中字符串对象类型
单引号和三单引号字符串都是String,不支持插值.
双引号字和三双引号符串在没有插入表达式(interpolated expression)的情况下双引号字符串为 java.lang.String; 如果有,则为 groovy.lang.GString
当创建如下的字符串:
def startingAndEndingWithANewline = '''
line one
line two
line three
'''
assert strippedFirstNewline.startsWith('\n')
字符串插值
字符串插值,可以用${}进行插值,如下所示
def name = 'Guillaume' // a_3_2 plain string
def greeting = "Hello ${name}"
//plain
def greeting2 = "Hello${'girl'}"
assert greeting.toString() == 'Hello Guillaume'
println(greeting)
println(greeting2)
GString toString
当一个方法(不管是在 Java 还是在 Groovy 中实现)期望一个java.lang.String,但我们传入一个 groovy.lang.GString 实例时,GString 的 toString() 方法会自动,透明地被调用.
String takeString(String message) {
assert message instanceof String
return message
}
def message = "The message is ${'hello'}"
assert message instanceof GString
def result = takeString(message)
assert result instanceof String
assert result == 'The message is hello'
GString 和 String 的哈希码
尽管插值字符串可以用来代替普通 Java 字符串,但它们与普通字符串在某一方面还是有区别的: 即它们的哈希码(hashCodes)是不一样的. 普通 Java字符串是不可变的,然而 GString 的结果字符串 表示是可变的,取决于它的插入值. 即使结果字符串相同,GString 和 String 还是有不同的哈希码.
//左边是插值字符串,右边是普通字符串,hashcode不一致
assert "one: ${1}".hashCode() != "one: 1".hashCode()
def key = "a"
def m = ["${key}": "letter ${key}"]
assert m["a"] == null
backslash
你会发现结果字符串的第一个字符是一个换行符. 可以用反斜杠(backslash)转义换行符来移除该字符:
def strippedFirstNewline = '''\ line one line two line three '''
assert !strippedFirstNewline.startsWith('\n')
unicode
groovy还可以支持unicode字符,如下所示
//欧元货币符号
def a='The Euro currency symbol: \u20AC'
printf(a)
结果The Euro currency symbol: €
字符
与 Java 不同,Groovy 没有明确的字符字面量. 但是,你可以通过 3 种不同的方式明确的将 Groovy 字符串转换为字符:
char c1 = 'A'
assert c1 instanceof Character
def c2 = 'B' as char
assert c2 instanceof Character
def c3 = (char)'C'
assert c3 instanceof Character
List
groovy的List本质是java.util.List,但是跟java有些区别,主要是改了下,让使用更方便。
- 创建的时候却像java的数组一样写 比如 下边的numbers不是一个数组,而是一个List(其实是ArrayList).
- List元素访问可以直接用[]访问List的元素,在java里必须用get()方法,方便了不少,比如L6.
- List元素访问可以从后往前,如L7,这个有点像python
- List增加一个元素可以用<<这个操作符
//定义了一个List
def numbers = [1,2,3]
assert numbers instanceof List
assert numbers.size() == 3
assert numbers[2] == 3
assert numbers[-1] == 3
//add
letters << 'e'
groovy的List可以放不同类型的东西,比如下边的List放了个int,一个String,一个boolean值
def heterogeneous = [1,"a",true]
数组Array
数组必须指明数据类型,访问数组元素的方法依然是[],和List一致。
String[] arrStr = ['Ananas','Banana','Kiwi']
assert arrStr instanceof String[]
assert !(arrStr instanceof List)
def numArr = [1,3] as int[]
assert numArr instanceof int[]
assert numArr.size() == 3
assert arrStr[2]=='Kiwi'
map
map实际数据类型是LinkedHashMap,但是创建访问有点像python的dictionary。
- 创建的时候可以用[]
- 访问的时候可以用[]或者.
- 创建时key可以放常量也可以放变量,很有意思,变量用()包含起来
def colors = [red: '#FF0000',green: '#00FF00',blue: '#0000FF']
assert colors['red'] == '#FF0000'
assert colors.green == '#00FF00'
colors['pink'] = '#FF00FF'
colors.yellow = '#FFFF00'
assert colors.pink == '#FF00FF'
assert colors['yellow'] == '#FFFF00'
assert colors instanceof java.util.LinkedHashMap
如下所示,上半段代码person里的,key是字符串“ff”,下半段代码里key是ff变量,即“name”字符串。
def ff = 'name'
def person = [ff: 'Guillaume']
assert !person.containsKey('name')
assert person.containsKey('ff')
person = [(ff): 'Guillaume']
assert person.containsKey('name')
assert !person.containsKey('ff')
数值
groovy会根据数值的大小自动分配数据类型,
//正数
def a = 1
assert a instanceof Integer
// Integer.MAX_VALUE
def b = 2147483647
assert b instanceof Integer
// Integer.MAX_VALUE + 1
def c = 2147483648
assert c instanceof Long
// Long.MAX_VALUE
def d = 9223372036854775807
assert d instanceof Long
// Long.MAX_VALUE + 1
def e = 9223372036854775808
assert e instanceof BigInteger
//负数
def na = -1
assert na instanceof Integer
// Integer.MIN_VALUE
def nb = -2147483648
assert nb instanceof Integer
// Integer.MIN_VALUE - 1
def nc = -2147483649
assert nc instanceof Long
// Long.MIN_VALUE
def nd = -9223372036854775808
assert nd instanceof Long
// Long.MIN_VALUE - 1
def ne = -9223372036854775809
assert ne instanceof BigInteger
String->boolean
String可以直接拿来当boolean值使用,空字符串相当于false,非空字符串相当于true.这里实际上隐式调用了asBoolean方法,转换成了boolean,这种隐式转换非常有意义,后面会看到。
assert (!'foo') == false
assert (!'') == true
三元运算符
if (string!=null && string.length()>0) {
result = 'Found'
} else {
result = 'Not found'
}
上边这段代码可以用三元运算符来简化
result = (string!=null && string.length()>0)?'Found':'Not found'
实际上利用string的boolean转化,我们还可以更简单,如下所示,其实上面的代码我在java里写过无数次,如果能直接用 string?'Found':'Not found'
来表示真的方便了很多,希望java也能引入类似的语法
result = string?'Found':'Not found'
三元简化
我们经常写如下代码,可以看到重复写了user.name
displayName = user.name ? user.name : 'Anonymous'
groovy想了个办法来简化,可以如下表示
displayName = user.name ?: 'Anonymous'
特殊操作符
空指针保护?
首先有个groovy类Person,然后看下边的代码
class Person {
/** 姓名 */
String name
/** * 为特定的人创建一个问候方法. * * @param otherPerson 待问候的人 * @return 问候信息 */
String greet(String otherPerson) {
"Hello ${otherPerson}"
}
}
Person[] arrStr = [new Person(),new Person(),null]
def person = arrStr[2]
def name = person.name
assert name == null
这里person会是null,那么person.name就肯定会触发空指针,groovy定义了一种操作符可以避免空指针,那就是加一个?
代码如下所示,这么写代码就方便多了,不用写那么多空判断,但是带来的隐患就是,最后出了问题,难以排查出原因,不好查哪里是null的源头。
//b1.groovy
/** * 空指针保护 * Created by fish on 17/1/7. */
Person[] arrStr = [new Person(),null]
def person = arrStr[2]
def name = person?.name
assert name == null
直接获取成员变量@
groovy获取成员变量,会直接调get方法,比如下边user.name会调用User的getName方法,我们这里name是Bob,但是我们复写了getName,所以getName得到Name: Bob,那如果我们想要的是Bob,怎么办呢?groovy提供了一种方法,加个@
//b2.groovy
class User {
String name
User(String name) { this.name = name}
String getName() { "Name: $name" }
}
def user = new User('Bob')
assert user.name == 'Name: Bob'
assert user.@name == 'Bob'
函数
groovy的函数定义一般都是用def定义,形参不需要写明类型,结束的时候用return返回,return可省略
def f(a) {
a * a;
}
def f(a,b) {
a * b;
}
assert f(10) == 100
assert f(5,10) == 50
函数和map
def f(a,b){
return b+a.x+a.y;
}
//a=x:2,y:3 b=1
println f(x:2,1,y:3);//输出6
println f(x:2,y:3,1);//输出6
类
groovy的类可以不用写构造函数,而在new的时候指明就可以了。
class Car {
String make
String model
}
Car car = new Car(make: 'Peugeot',model: '508')
assert car.make == 'Peugeot'
ref
http://docs.groovy-lang.org/next/html/documentation/
http://groovy.zeroleaf.com/core-syntax.html
http://groovy.zeroleaf.com