1 引言
Groovy是用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。 使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。
Groovy是一种基础JVM(Java虚拟机)的敏捷开发语言,他结合了Python、Ruby和Smalltalk的特性,Groovy代码能够于Java代码很好的结合,也能用于扩展现有代码。 由于其运行在JVM的特性,Groovy可以使用其他Java语言编写法的库。
for(int i=0; i<10; i++) {
...
}
10.times{
...
}
在使用Groovy编程时,Java有的Groovy几乎都有。Groovy同样扩展了java.lang.Object类,Groovy类就是Java类,Java语义都保留下来了,所以使用Groovy编写的表达式和语句, 对于Java程序员而言,理解它没有任何障碍。
Groovy虽然支持Java的语法但它并没有强迫我们学习新的类和库,而是通过向JDK中各种类添加方法,所以说Groovy扩展了JDK,这些扩展称之为GDK (Groovy JDK)。
Java中可以使用java.lang.process与系统级进程进行交互,例如,我们在代码中调用git的help命令并把help的内容打印出来,用Java的实现代码如下:
package com.zs.groovy;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ExecuterProcessor {
public static void main(String[] args) {
try {
// 获取process实例
Process process = Runtime.getRuntime().exec("git help");
// 读取输入流
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
转化为 groovy 语法:
print "git help".execute().text
2 基本语法
2.1 标识符
2.2 字符串
Groovy允许实例化java.lang.String类来定义一个字符串对象,同样地,也可以通过实例化groovy.lang.GString类定义一个字符串对象,两者可以混合使用。
def a = 'i am zhaoshuai-lc'
def b = '''
i am zhaoshuai-lc
and
i am a male
'''
// 说明:用单引号或三个单引号定义的字符串不支持混合编程
def c = "hello zhaoshuai-lc"
> def name = "zhaoshuai-lc"
> def _name = "hello ${name}"
> print _name
hello zhaoshuai-lc
三个双引号引起来的字符串:
用"""引号引起来的字符串行为上和双引号引起来的字符串是一样的,不同之处在于它代表多行字符串,就像三个单引号定义的字符串。例如:
def name = 'zhaoshuai-lc'
def template = """
Dear $name
i love U
"""
print(template)
如果是使用内置变量类型定义的变量,一经定义,后面是不可以更改变量类型的。但是Groovy也提供了类似javascript中的any定义任意变量类型的关键字def。
class Example {
static void main(String[] args) {
def _Name = 1;
_Name="it飞牛";
println(_Name);
}
}
//打印如下:
it飞牛
2.3 数值类型
byte -这是用来表示字节值。例如2。
short -这是用来表示一个短整型。例如10。
int -这是用来表示整数。例如1234。
long -这是用来表示一个长整型。例如10000090。
float -这是用来表示32位浮点数。例如12.34。
double -这是用来表示64位浮点数,这些数字是有时可能需要的更长的十进制数表示。例如12.3456565。
char -这定义了单个字符文字。例如“A”。
Boolean -这表示一个布尔值,可以是true或false。
String -这些是以字符串的形式表示的文本。例如,“Hello World”。
不同类型数值进行算术运算的规则:
对于二元运算符,两个不同类型的数值进行运算后它们的结果按照以下规则确定
对于byte、char、short、int这几种类型之间运算的结果为int
涉及long与byte、char、short、int之间运算的结果为long
涉及BigInteger与其它类型数值之间的运算结果为BigInteger
BigDecimal与byte、char、short、int之间的运算结果为BigDecimal
float、double与BigDecimal之间的运算结果为double
两个BigDecimal之间的运算结果为BigDecimal
2.4 数组与集合
Groovy没有自己的集合类型,它的List类型实际上用的就是JDK中的java.util.List包。当我们定义一个集合对象,Groovy默认采用Java.util.ArrayList类型。
> def numbers = [1, 2, 3]
> assert numbers instanceof java.util.List
> assert numbers.size() == 3
也可以在集合中放置不同类型的元素,例如:
def numbers = [1, 2, 3, true, 'false']
默认定义的集合对象属于Java.util.ArrayList类,也可以用as运算符,强制定义List接口的其它实现类的对象,例如:
> def list = [1, 2, 3, 4] as LinkedList
> assert list instanceof LinkedList
> def list = [1, 2, 3, 4] as LinkedList
> assert 1 == list[0]
> assert 4 == list[-1]
> list << true
> print list[4]
true
Groovy 可以定义多维集合,例如:
def multi = [[0, 1], [2, 3]]
Groovy中数组和集合的表示方式相同,也就是说Groovy复用list的表示形式来表示数组,但必须显式的声明数组的类型,例如:
> String[] arrStr = ['zhaoshuai-lc', 'zhaoshuai-la', 'zhaoshuai-lb']
> assert arrStr instanceof String[]
> assert !(arrStr instanceof List)
使用as运算符,强制转化为要定义的类型:
> def intArr = [1, 2, 3] as int[]
> assert intArr instanceof int[]
也可以定义多维数组:
> def _matrix = new Integer[2][3]
> assert _matrix.size() == 2
声明时不指定数组元素个数:
> Integer[][] arr
> arr = [[1, 2, 3], [2, 3]]
> print arr.length
2
访问数组元素时按照和list—样的方式,使用下标运算符[],例如:
> String[] strArr = ['zjaosuia', 'dafas', 'erqrw']
> print strArr[2]
erqrw
Java 风格化:
> def primes = new int[]{2, 3, 4, 1, 6}
> assert primes.length == 5 && primes.sum() == 16
>
> def pets = new String[]{'zhaoshuai', '-', 'lc'}
> assert pets.size() === 3 && pets.sum() == 'zhaoshuai-lc'
>
> String[] groovyArr = ['zhaoshuaiA', '-A', 'lcA']
> assert groovyArr.every { it -> it.contains('A') }
2.4.1 List 语法详解
groovy 列表使用索引操作符 [] 索引。列表索引从 0 开始,指第一个元素。groovy 中的一个列表中的数据可以是任意类型。这 java 下集合列表有些不同,java 下的列表是同种类型的数据集合。
List.reverse() 可以实现列表反转。
调用 List.sort() 可以实现列表排序。
> def list1 = []
> def list2 = [1, 2, 3, 4]
> list2.add(12)
> list2.add(12)
> println list1.size()
> println list2.size()
0
6
1、搜索-find
class Main {
static void main(String[] args) {
def list = [1, 2, 3, 1, 2, 3];
// find:返回第一个符合条件的项
def find = list.find( item -> item == 1)
assert 1 == find
// findAll:返回所有符合条件的项
def findA = list.findAll( item -> item == 1)
assert [1, 1] == findA
// findIndexOf:返回满足条件的第一个元素的下标值。
def index = list.findIndexOf(item -> item == 1)
assert 0 == index
}
}
2、排序-sort、reverse
class Main {
static void main(String[] args) {
def list = [1, 2, 3, 1, 2, 3];
// sort-正序排序
print list.sort();
// sort-倒叙排序
print list.sort((a, b) -> b - a)
// reverse:将原list倒序,返回一个新的list
print list.reverse();
}
}
3、返回新数组-collect、tail
class Main {
static void main(String[] args) {
def list = [1, 2, 3, 1, 2, 3];
// collect:返回一个新的list,他可以接受一个闭包参数或者无参。类似js中map。it是闭包中自带的隐式变量;
println list.collect(item -> item + 100)
// tail:返回一个新的list,它包含list中的所有的元素(除了第一个元素)
println list.tail(); // [2, 3, 1, 2, 3]
}
}
4、遍历 each、eachWithIndex
class Main {
static void main(String[] args) {
def list = [1, 2, 3, 1, 2, 3];
// each:普通的迭代遍历
list.each(item -> print item)
//eachWithIndex:他的作用和each一样,但是他要传入一个闭包,有两个参数,一个是值,一个是索引。
list.eachWithIndex { int entry, int i -> println("${entry}--${i}")}
}
}
every、any、first、last、max、min、count、unique
class Main {
static void main(String[] args) {
def list = [1, 2, 3, 1, 2, 3];
// every:接收一个闭包,返回为一个布尔值,当所有条件都满足时才返回true
println list.every(item -> item > 0)
// any:和every用法一样,只要有一个为true,则返回true
println list.any(item -> item > 0)
//返回第一个数据
println(list.first());
//返回最后一个数据
println(list.last());
//返回最大值
println(list.max());
//返回最小值
println(list.min());
//返回总和
println(list.sum());
//返回某项出现的次数
println(list.count(3));
//返回去重后的数组
println(list.unique());
}
}
5、分组
class Main {
static void main(String[] args) {
def items = [[name: "tony", age: 4], [name: "tony", age: 5], [name: "alan", age: 16]]
def groups = items.groupBy { it.name }
println(groups);
// [tony:[[name:tony, age:4], [name:tony, age:5]], alan:[[name:alan, age:16]]]
}
}
6、包含
class Main {
static void main(String[] args) {
def list = [1, 2, 3, 1, 2, 3];
def list2 = [1, 2, 3, 4];
println(list.containsAll(list2));
println(list2.containsAll(list));
}
}
2.5 Map映射
Groovy的map对象 就是LinkedHashMap的实例
class Example {
static void main(String[] args) {
def mp = ["TopicName" : "Maps", "TopicDescription" : "Methods in Maps"]
println(mp.get("TopicName"));
println(mp.get("Topic"));
}
}
2.6 对象运算符
安全导航运算符(safe navigation operator) 主要作用为避免出现NullPointerException异常,如果出现空指针异常,使用安全导航运算符将返回null,而不是抛出异常。例如:
> class Person{
> int id
>
> Person(int id) {
> this.id = id
> }
>
> int getId() {
> return id
> }
>
> void setId(int id) {
> this.id = id
> }
>
> }
> def person = new Person(3451)
> def _person = person.find{ item -> item.id == 345}
> println _person
> println _person?.id
null
null
直接字段访问运算符(Direct field access operator) 使用该运算符可以不用调用get方法而直接获取字段的值。例如:
> class User {
> public String name;
>
> User(String name) {
> this.name = name;
> }
>
> String getName() {
> "Name: ${name}"
> }
> }
>
> def user = new User("Bob")
> print user.name
> assert user.name == 'Name: Bob'
Name: Bob
> class User {
> public String name;
>
> User(String name) {
> this.name = name;
> }
>
> String getName() {
> "Name: ${name}"
> }
> }
>
> def user = new User("Bob")
> print user.@name
> assert user.@name == 'Bob'
Bob
2.7 正则表达式
Groovy使用~”pattern”
来支持正则表达式,它将使用给定的模式字符串创建一个编译好的Java Pattern 对象。Groovy也支持 =~
(创建一个Matcher)和 ==~
(返回boolean,是否给定的字符串匹配这个pattern)操作符。
> import java.util.regex.Pattern
>
> def p = ~/foo/
> assert p instanceof Pattern
> def res = p.matcher('foo').matches()
> print res
true
> import java.util.regex.Matcher
>
> def text = 'i am your father'
> def res = text =~ /father/
> assert res instanceof Matcher
> print res.matches()
false
> import java.util.regex.Matcher
>
> def text = 'i am your father'
> def res = text ==~ /father/
> assert res instanceof Boolean
> print res
false
3 类与脚本
Groovy提供了两种代码方式,一种是脚本一种是类,首先我们定义一个名为Main.groovy的类。代码如下:
class Main{
static void main(String[] args) {
print 'hello zhaoshuai-lc'
}
}
print 'hello zhaoshuai-lc'
print 'hello zhaoshuai-lc'
上面的脚本实由groovy.lang.Script类编译成一个class文件,把脚本代码拷贝到groovy.lang.Script类的run方法中进行执行,实际运行的代码形如下面的内容:
执行的步骤如下:
Main.class继承Script类
把脚本的主体内容复制到run方法内
然后自动生成main()方法,最后运行run()
方法 可以在脚本中定义方法,例如:
> int fib(int n) {
> n < 2 ? 1 : fib(n - 1) + fib(n - 2)
> }
>
> assert fib(10) == 89
创建的脚本类在编译后会把脚本中的所有方法装配到run方法中,这些对于用户来说都是透明的。
变量 在脚本中定义变量无需声明变量的类型,例如:
int x = 1
int y = 2
assert x+y == 3
×= 1
y = 2
assert x+y == 3
这两者在语义上有一些差别,上面的例子中声明的变量属于局部变量,只在run方法内部可见,而下面的无声明变量定义对于其它方法可见, 这对于脚本与其它应用程序共享数据就显得很重要了。
Groovy类是数据的集合和对该数据进行操作的方法的载体,类的数据和方法用于表示问题域中的一些现实世界对象。 Groovy中的类声明了该类定义的对象的状态(数据)和行为。因此,Groovy类描述了该类的实例字段和方法。
在任何编程语言中,总是使用private关键字隐藏实例成员,通过提供getter和setter方法来相应地设置和获取实例变量的值。例如下面的代码:
内部类定义在另一个类中,外层类可以访问内部类,内部类也可以使用外层类的成员变量,即使是私有的。其它类不能访问内部类。内部类的示例如下:
class Main {
static void main(String[] args) {
def outer = new Outer()
outer.name = 'zhaoshuai-lc'
outer.callInnerMethods()
}
}
class Outer {
String name
def callInnerMethods() {
new Inner().methodInner()
}
class Inner {
def methodInner() {
print name
}
}
}
extends是用于继承类的关键字,我们通过一个示例介绍groovy中如何继承其它类:
class Main {
static void main(String[] args) {
def sub = new Sub('zhaoshuai-lc')
}
}
class Outer {
public String name
Outer(String name) {
print name
}
}
class Sub extends Outer {
Sub(String subName) {
super(subName)
}
}
抽象类表示通用概念,因此它不能被实例化,但可以被继承。抽象类中的抽象方法只有方法的定义而没有方法的实现,它的实现通过继承它的类来完成,定义抽象类通过关键字 abstract来声明,抽象方法也是同样的。
接口定义了类需要遵守的规范,接口仅定义需要实现的方法的列表,但是不定义方法实现。 接口需要使用interface关键字声明接口,接口的方法总是公开的,在接口中使用受保护或私有方法是一个错误。
class Example {
static void main(String[] args) {
Student st = new Student();
st.StudentID = 1;
st.Marks1 = 10;
println(st.DisplayMarks());
}
}
interface Marks {
void DisplayMarks();
}
class Student implements Marks {
int StudentID
int Marks1;
void DisplayMarks() {
println(Marks1);
}
}
4 闭包
闭包可以接收入参
闭包可以引用外部变量
class Example {
static void main(String[] args) {
def str1 = "Hello";
def clos = {param -> println "${str1} ${param}"}
clos.call("World");
// We are now changing the value of the String str1 which is referenced in the closure
str1 = "Welcome";
clos.call("World");
}
}
//打印
Hello World
Welcome World