一个java程序员刚开始使用Groovy的时候,不可避免的满脑子想的都是java,当熟悉Groovy后就会代码会逐渐符合Groovy语言习惯,从而变得更加高产。下面介绍一下一些通用的Groovy语法:
1、不需要分号
学过C/C++/C#/java的同学都会对分号很熟悉,我们使用的如此频繁,几乎放在每一行的末尾。Groovy支持99%的java语法,甚至可以在Groovy代码中直接粘贴java代码,然而在Groovy中分号是可选的,你可以省略他们。
2、return关键字可省略
在Groovy中,方法的最后一句表达式可作为返回值返回,而不需要return关键字。
String toString() { return "a server" }
String toString() { "a server" }
但有时候省略return
关键字并不是一个好主意
def props() {
def m1 = [a: 1, b: 2]
m2 = m1.findAll { k, v -> v % 2 == 0 }
m2.c = 3
m2
}
在这种情况下,明确的使用return
关键字会更具可读性。
3、def 和 类型
在Groovy中使用def
关键字定义的变量类型都是Object,定义方法是,通常可以省略def
关键字,尽量别def
和类型混用,避免这种写法def String name = "Guillaume"
。
定义方法时,如果参数没有类型,我们可以省略def
:
void doSomething(param1, param2) { }
定义类的构造器时,避免添加def
关键字:
class MyClass {
MyClass() {}
}
4、默认是public权限
默认情况下,Groovy的classes和方法是public
权限,所以我们可以省略public
关键字,除非我们想使用private
:
class Server {
String toString() { "a server" }
}
5、省略圆括号()
Groovy允许你在顶级表达式中省略圆括号,例如println
:
println "Hello"
method a, b
某些情况下,Groovy不允许省略圆括号,比如:
def foo(n) { n }
println foo 1 // won't work
6、Classes是一等公民
在Groovy中.class
后缀不是必须的,类似于java的instance
。例如:
connection.doPost(BASE_URI + "/modify.hqu", params, ResourcesResponse.class)
使用GStrings,并使用class一等公民:
connection.doPost("${BASE_URI}/modify.hqu", params, ResourcesResponse)
7、Getters and Setters
getter和setter方法来自属性,Groovy中,提供了一个简短的获取和设置属性的方法,你可以省略getter和setter:
resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME
resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME
resourcePrototype.setName("something")
resourcePrototype.name = "something"
当你在Groovy中创建一个beans的时候,通常我们称为POGOS(Plain Old Groovy Objects),Groovy会自动帮我们创建getter/setter方法,所以你可以把
class Person {
private String name
String getName() { return name }
void setName(String name) { this.name = name }
}
替换为
class Person {
String name
}
当你对getter/setter方法有特殊要求,你尽可提供自己的方法,Groovy默认的getter/setter方法会被替换。
8、使用命名的参数初始化beans和默认的构造器
有一个bean
class Server {
String name
Cluster cluster
}
初始化一个实例的时候你可能会这样写:
def server = new Server()
server.name = "Obelix"
server.cluster = aCluster
其实你可以用带命名的参数的默认构造器,会大大减少代码量:
def server = new Server(name: "Obelix", cluster: aCluster)
9、在同一个bean中使用with()来重复某一个操作
当更新一个实例的时候,你可以使用with()来省略相同的前缀,java中你必须这样写:
server.name = application.name
server.status = status
server.sessionCount = 3
server.start()
server.stop()
Groovy中则可以使用with():
server.with {
name = application.name
status = status
sessionCount = 3
start()
stop()
}
10、Equals 和 ==
Java里的==
等同于Groovy里的is()
方法,Groovy中的==
是更智能的equals()
,比较两个类的时候,你应该使用a.is(b)
,而不是==
。
Groovy中的==
可以自动避免NullPointerException
异常:
替换
status != null && status.equals(ControlConstants.STATUS_COMPLETED)
为
status == ControlConstants.STATUS_COMPLETED
11、GStrings字符串分行
Java中,字符串过长需要换行时我们一般会这样写:
throw new PluginException("Failed to execute command list-applications:" +
" The group with name " +
parameterMap.groupname[0] +
" is not compatible group of type " +
SERVER_TYPE_NAME)
Groovy中你可以用 \ 字符:
throw new PluginException("Failed to execute command list-applications: \
The group with name ${parameterMap.groupname[0]} \
is not compatible group of type ${SERVER_TYPE_NAME}")
或者使用多行字符串"""
:
throw new PluginException("""Failed to execute command list-applications:
The group with name ${parameterMap.groupname[0]}
is not compatible group of type ${SERVER_TYPE_NAME)}""")
Groovy中,单引号引起来的字符串是java字符串,不能使用占位符来替换变量,双引号引起的字符串则是java字符串或者Groovy字符串。
12、一些操作数据结构的方法
def list = [1, 4, 6, 9]
// Map的key默认是字符串类型,可以省略双引号
//你可以用()将keys包起来插入一个变量或者类作为key,例如 [(variableStateAcronym): stateName]
def map = [CA: 'California', MI: 'Michigan']
def range = 10..20
def pattern = ~/fo*/
// <<相当于 add()
list << 5
// 调用包含方法
assert 4 in list
assert 5 in list
assert 15 in range
// subscript notation
assert list[1] == 4
// map添加key-value对
map << [WA: 'Washington']
// subscript notation
assert map['CA'] == 'California'
// property notation
assert map.WA == 'Washington'
// 匹配正则表达式
assert 'foo' =~ pattern
13、switch方法
Groovy的switch方法更具实用性,可以接受更多的类型:
def x = 1.23
def result = ""
switch (x) {
case "foo": result = "found foo"
// lets fall through
case "bar": result += "bar"
case [4, 5, 6, 'inList']: result = "list"
break
case 12..30: result = "range"
break
case Integer: result = "integer"
break
case Number: result = "number"
break
case { it > 3 }: result = "number > 3"
break
default: result = "default"
}
assert result == "number"
types也可以调用isCase()
方法判断一个值是否等于某一个case。
14、Import 别名
在java中使用两个类名相同但包名不同的两个类,像java.util.List
和 java.wt.List
,你必须使用完整的包名才能区分。Groovy中则可以使用import别名:
import java.util.List as jurist
import java.awt.List as aList
import java.awt.WindowConstants as WC
也可以静态引入方法:
import static pkg.SomeClass.foo
foo()
15、判断是否为真
所有类型都能转成布尔值,比如null
和void
相当于0或者相当于false
,其他则相当于true
,所以替换:
if (name != null && name.length > 0) {}
为
if (name) {}
在Groovy中可以在类中添加asBoolean()
方法来自定义是否为真。
16、安全的取值
在java中,你要获取某个对象的值必须要检查是否为null
,这就造成了大量的if
语句,像这样的:
if (order != null) {
if (order.getCustomer() != null) {
if (order.getCustomer().getAddress() != null) {
System.out.println(order.getCustomer().getAddress());
}
}
}
Groovy中可以使用?.
安全的取值:
println order?.customer?.address
17、断言
检查方法传入的参数是否为空,你可以使用assert
来检查:
def check(String name) {
// name non-null and non-empty according to Groovy Truth
assert name
// safe navigation + Groovy Truth to check
assert name?.size() > 3
}
18、三目运算符
三目运算符通常用来给定默认值,我们经常这样写:
def result = name != null ? name : "Unknown"
多亏了Groovy的真值,空值检查可以简化为’name’,并且可以省略?
和:
之间的变量:
def result = name ?: "Unknown"
19、捕获任何异常
如果你实在不想关心try
块里抛出何种异常,你可以简单的捕获所有异常,并且可以省略异常类型:
try {
// ...
} catch (Exception t) {
// something bad happens
}
省略异常类型:
try {
// ...
} catch (any) {
// something bad happens
}
这里的any并不包括Throwable
,如果你真想捕获everything,你必须明确的标明你想捕获Throwable