Groovy 是一门基于 JVM 的动态语言,既可以面向对象编程,又可以用作纯粹的脚本语言。在学习 Java 语法的情况下会很容易学习,下面就是 Groovy 和 Java 语法的不同之处的学习。
学习教程:https://www.kancloud.cn/kancloud/learnxinyminutes/58931
1. 与Java的异同
Groovy可以作为 Java 的脚本语言使用,因为其运行于 JVM 的特性,其可以使用其他Java库。
下面是其和Java 相异的地方:
- Groovy 之中包括了 Java 之中不支持的静态和动态类型(使用关键字 def)
- 提供 List 和 Maps 的原生语法
- 原生支持 正则表达式,字符串内嵌表达式,Null条件运算符,自动空指针检查
- Groovy 源代码文件可以作为未编译的脚本执行。Groovy脚本在执行之前完成解析,编译和生成。
Groovy之中动态类型的特性十分方便,可以将不同的基本类型添加到一个 collections 之中。
1.1 Java 和 Groovy 的类的区别
- 不需要public 修饰符。Groovy 的默认访问修饰符就是 public。
- 不需要类型说明。Groovy 也不关心变量和方法参数的具体类型。
- 不需要 getter/setter 方法。连IDE自动生成都不需要。当然,也支持写 getter 和 setter
- 不需要构造函数。注意,此处的“不需要”,前提条件是其操作比较常规,例如只是给一些参数进行赋值,而不是说不可以有。在需要独特业务的情况下,可以自己进行业务结合的构造函数。
- 不需要 return。当然,Groovy不可能智能到你想要什么都知道。实际上,在需要 return 的情况下,如果省略 return,那么Groovy 会自动将整个程序的最后一句作为返回值。如果不是这种情况,那么需要自己指定返回值
- 不需要()。在 Groovy 之中,Groovy 的方法调用可以省略(),但是构造函数除外。
- Groovy 不需要分号作为结尾。
2. 字符串处理
相对于 Java 而言,Groovy 对于字符串的操作简单很多。
在 Groovy之中,单引号和双引号都可以定义一个字符串常量,不同的是,单引号标记的是纯粹的字符串常量,但是双引号的字符串可以对字符串里面的表达式做运算。
class Attribute {
static void main(args){
println "Hello world"
def str1='single quota '
def str2="double quota "
println(str1+str1.getClass().name)
println(str2+str2.getClass().name)
}
}
程序运行之后可以看到输出为:
Hello world
single quota java.lang.String
double quota java.lang.String
但是不可以对单引号之中的字符串的表达式做运算,下面举个例子:
class Attribute {
static void main(args){
def name="John"
println 'single quota can not do operation:$name'
println "double quota can do operation:$name"
}
}
其输出为:
single quota can not do operation:$name
double quota can do operation:John
可见双引号之中的字符串可以做一些操作,但是单引号之中的不可以。
双引号可以直接进行表达式计算的功能很好用,可以直接做很多计算,不用 Java 之中的 + 进行一点点的串联了。嵌套的规则是,一个美元符号紧跟着一对花括号,花括号里放表达式,比如name,name,{1+1}等等,只有一个变量的时候可以省略花括号,比如$name。
3. 集合
Groovy 完全兼容了 Java 的集合,并且进行了扩展,在扩展之中,声明,迭代,查找集合元素等等都会变得非常容易。常见的集合有 List,Set,Map和Queue,这边只介绍 List 和 Map。
3.1 List
在Java 之中我们使用 List, 例如 ArrayList, 需要New 一个 ArrayList 的类,在 Groovy 之中直接定义就好:
class Attribute {
static void main(args){
def numList=[1,2,3,4,5]
println numList.getClass()
}
}
输出为:
class java.util.ArrayList
Just for a en
可见,在定义一个变量并且对其赋值之后,其会直接转换成一个 List. 这里面的输出就是一个 ArrayList.
在定义好集合之后,怎么访问集合之中的元素?Groovy 之中,可以直接使用下标来对某个集合进行操作.
class Attribute {
static void main(args){
def numList =[1,2,3,4,5,6];
println numList.getClass().name
println numList[1]//访问第二个元素
println numList[-1]//访问最后一个元素
println numList[-2]//访问倒数第二个元素
println numList[1..3]//访问第二个到第四个元素
}
}
对于迭代的元素,还有迭代的方法 each 进行操作.该方法接受一个 闭包 (closure) 作为其参数.
class Attribute {
static void main(args){
def numList =[1,2,3,4,5,6];
println numList.getClass().name
println numList[1]//访问第二个元素
println numList[-1]//访问最后一个元素
println numList[-2]//访问倒数第二个元素
println numList[1..3]//访问第二个到第四个元素
numList.each {
println it
}
}
}
在这里,it 就是后来迭代的元素.
3.2 Map
Map 之中的值是一个 K:V 键值对
class Attribute {
static void main(args) {
def map1=['width':1024,'height':2048]
println(map1.getClass().name)
println(map1['width'])
println(map1.height)
}
}
上面的两种方式都可以取出 key-value 的 value.
下面示例是 map 的迭代:
class Attribute {
static void main(args) {
def map1=['width':1024,'height':2048]
println(map1.getClass().name)
println(map1['width'])
println(map1.height)
map1.each{
println("Key:${it.key};Value:${it.value}")
}
}
}
输出:
java.util.LinkedHashMap
1024
2048
Key:width;Value:1024
Key:height;Value:2048
Groovy 对于集合,还提供了诸如 collect, find, findAll 等等方法.
4. 方法
4.1 括号是可以省略的
之前的代码之中,对于方法的调用也省略了括号.此处就不再叙述下面的区别.
4.2 return 可以省略
之前也提到过,return 可以直接省略,省略的话,是直接将最后一句的值作为 return
4.3 代码块可以作为参数传递
在 Groovy 之中,代码块可以作为参数传递.但是结合上面的特性,最后的闭包就会比较优雅.以集合的each 方法为例:
//基于死板的写法其实是这样
numList.each({println it})
//我们格式化一下,是不是好看一些
numList.each({
println it
})
//好看一些,Groovy规定,如果方法的最后一个参数是闭包,可以放到方法外面
numList.each(){
println it
}
//然后方法可以省略,就变成我们经常看到的啦
numList.each {
println it
}
5. Java Bean
在Groovy 之中,上面提及到我们并不需要 getter/setter 来进行属性的赋值等等,例如:
class Attribute {
static void main(args) {
Person p = new Person()
println("Name is ${p.name}")
p.name="Shawn"
println("Name is ${p.name}")
}
}
class Person{
private String name;
}
其输出为:
Name is null
Name is Shawn
可以看到,在第一个1个${p.name}
之中,其得到的值为 null. 在第二个之中,经过赋值,其得到的值就是 Shawn.
在 Groovy 之中,可以不定义成员变量,而是直接使用 getter/setter 方法,一样可以被识别成属性并且被访问.
class Attribute {
static void main(args) {
Person p = new Person()
println("Name is ${p.name}")
p.name="Shawn"
println("Name is ${p.name}")
println("Age is ${p.age}")
}
}
class Person{
private String name;
public int getAge(){
12
}
}
得到的结果:
Name is null
Name is Shawn
Age is 12
但是如果在这种情况下,我们不可以进行设置值. 因为我们只定义了 getAge()
方法,而没定义其 setter 方法.同样的,如果定义了相应的 getter/setter 方法的话,也会让使用的人认为其是一个相应的属性.
6. 闭包
闭包是 Groovy 的一个非常重要的特性.
问过同事,之前自己认为闭包和正常声明一个方法区别不大,实际上在辨析过后发现,其都是用来实现某种功能,和 java的匿名函数类似,虽说没有什么只有闭包没有正常代码(比如for 循环等) 做不到的,但是闭包可以显著减少代码量.那么下面就对于闭包做一定的梳理:
6.1 初始闭包
前面讲过,闭包就是一段代码块,下面以each 为例子,用闭包的 it 变量来将整个基础的闭包实现:
class Attribute {
static void main(args) {
def clos={println("Hello world")}
println("Executing closure")
clos()
}
}
输出为:
Executing closure
Hello world
可以看到其 def clos
之中的代码在 clos() 的地方才被执行.
6.2 向闭包传递参数
闭包之中也可以传递参数,像这样:
class Attribute {
static void main(args) {
def sum={a,b -> println(a+b)}
sum(2,4)
}
}
输出为:
6
6.3 闭包传递参数列表之外变量
当然,闭包也可以使用参数列表之外的变量,类似于:
class Attribute {
static void main(args) {
def x=5
def multiplyBy={num -> num*x}
println multiplyBy(10)
}
}
输出:
50