Groovy快速入门

Groovy简介

Groovy是基于Java平台开发的一门强大的、具有Optional类型,多功能性的动态语言,它具有静态类型和静态编译的功能。为了提高在java平台的开发效率,它的语法设计的很简洁,易学。和java无缝集成,从而使自己的项目具有强大的特性,比如脚本功能、DSL(Domain-Specific Language)语言编写,运行时和编译时元编程(meta-programming)以及函数式编程。

Groovy优势

  • 语法简洁,可读性强,并且很容易上手
  • 功能强大,具有闭包特性,自动构建,元编程,函数式编程,Optional类型以及静态编译的功能
  • 集成性强,与Java语言或者一些第三方库无缝接入
  • DSL语言编写,语法灵活,扩展性强,使项目具有高级配置与可定制的机制,可读性强的特点
  • 完整的生态系统,涉及Web开发、reactive应用,并发性、异步的库、测试框架、构建工具(Build Tools)、代码分析、GUI构建
  • 脚本测试,可以写一些简单的、可维护的测试用例,来完成自动化构建任务

安装Groovy

Groovy下载链接
下载后,把压缩包解压到相应的位置,然后再环境变量的Path里面添加解压后的路径(到解压的bin目录下)。配置好后,然后运行groovy -v,可以看到如下图

图1.png

到这里,就安装好了。

Groovy IDE

图2.png

Hello Groovy

运行groovyconsole之后,稍等,可以看到启动的Groovy自带的编辑器。输入第一句代码:

println "Hello Groovy!"

然后按CTR+R就可以得到如下输出

groovy> println "Hello Groovy!" 

Hello Groovy!

或者我们save as到一个相应的位置保存为hello.groovy,然后cd到相应的目录下面,运行groovy hello.groovy,得到结果也一样,如下图

图3.png

Java&Groovy不同点

  • 默认含有import ,引入包无须在前面再申明import,比如java.io.*java.lang.*等等
  • 方法多元化(Multi-methods)Groovy的参数类型决定于代码运行时,Java正好相反,Java参数类型决定于编译时,主要用申明的类型决定。比如举个例子
    Hello.groovy
void method(String arg){
    println "this arg is string type";
}
void method(Object arg){
    println "this arg is Object type";
}

Object obj = "hello Groovy";
method(obj);

输出结果为

this arg is string type

Hello.java

public class Hello{
    void method(String arg){
        System.out.println("this arg is string type");
    }
    void method(Object arg){
        System.out.println("this arg is Object type") ;
    }
    public static void main(String[] args){
        Object obj = "hello Groovy";
        Hello hello = new Hello();
        hello.method(obj);
    }
}

输出结果为

图4.png

  • Array初始化

java初始化一个Array,一般是这样

int[] array = {1,2,3};

但是在Groovy里面{...}代表的是一个闭包(closures),所以Groovy不能和Java这样申明。我们应该这样申明

int[] array = [1,2,3]
  • 包范围可视性

    比如一个类

    class Person{
      String name
    }

    Groovy里面,没有可视化修饰符的属性,都是公有的,并且会生成gettersetter方法。如果要私有化这个属性,可以加注解@PackageScope,如下

class Person {
    @PackageScope String name
}
  • ARM 块
    ARM(Automatic Resource Management)自动化资源管理,在Java7开始引入,但是Groovy不支持,所以Groovy通过闭包的形式提供了各种各样的依赖方法来替换,实现效果是一样的。比如:
Path file = Paths.get("/path/to/file");
Charset charset = Charset.forName("UTF-8");
try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }

} catch (IOException e) {
    e.printStackTrace();
}

可以写成:

new File('/path/to/file').eachLine('UTF-8') {
   println it
}

或者写成和上面Java版本更像的代码:

new File('/path/to/file').withReader('UTF-8') { reader ->
   reader.eachLine {
       println it
   }
}
  • 内部类
    Groovy的匿名内部类和内嵌类和Java的实现方式是一样的,但是 Groovy不支持y.new X()这种实现方式,需要使用 new X(y),如下
    Java
public class Y {
    public class X {}
    public X foo() {
        return new X();
    }
    public static X createX(Y y) {
        return y.new X();
    }
}

Groovy

public class Y {
    public class X {}
    public X foo() {
        return new X()
    }
    public static X createX(Y y) {
        return new X(y)
    }
}
  • Lambda 表达式
    Java8是支持Lambda表达式的,比如
Runnable run = () -> System.out.println("Run");
list.forEach(System.out::println);

但是Groovy是不支持,取而代之的是使用闭包实现的一样的效果

Runnable run = { println 'run' }
list.each { println it } // or list.each(this.&println)
  • GStrings

Java里面字符串是"xxxxx"这样的形式,但是在Groovy里面这种形式叫GString(Groovy String)或者String类型,当使用($)符号引用类型是,它会自动转换为GString类型,反之,为String类型。

  • 字符串和字符字面量
    当使用'xxx'形式使用的时候,它的类型为字符串(String),当使用"xxx"的时候,参考上面GString说明

  • 基本类型和封装性
    由于Groovy一切类型皆对象,所以它会自动把基本类型封装成对象,这一点和Java规范不同,比如

int i
m(i)
//方法1
void m(long l) {           
  println "in m(long)"
}
//方法2
void m(Integer i) {        
  println "in m(Integer)"
}

如果是Java,自然会去执行方法1,但是Groovy则会执行方法2

  • ==的不同

Java==指的是基本类型相等或者是对象的引用相等,但是在Groovy中,Java==含义转换为a.compareTo(b)==0,如果两边都实现了Comparable接口的话,而Groovy==的含义指的是a.equals(b),对象引用是否相等,则是使用a.is(b)

  • 转换
    java的自动转换只能向下转换,Groovy则进行相应的扩展,具体如下

图5.png

Y 表示 Groovy 可以执行的转换。D表示的是在动态编译或显式转换时 Groovy 能够执行的转换。T 表示 Groovy 可以执行的转换,但数据被截断了。B表示装箱/拆箱操作。N表示Groovy不能实行的转换。

  • 扩展的关键字
as

def

in

trait

Groovy开发套件

IO操作

Groovy提供了一些IO操作的帮助类,这里提供几个常用的API
1. java.io.File
2. java.io.InputStream
3. java.io.OutputStream
4. java.io.Reader
5. java.io.Writer
6. java.nio.file.Path

  • 读文件
    通过Groovy读取文件很简单,举个例子,先在E:/Android/Groovy/workspace目录下创建一个read.txt文件,然后编写代码
new File('E:/Android/Groovy/workspace','read.txt').eachLine{ line ->
    println line
}

File对象有两个参数,一个是文件的路径,一个是文件的文件名,然后eachLine方法就可以读取到文件内容

这是通过Groovy的IO方法读取的一个txt文件,

其实,在FileAPI里面还可以查到eachLine还有很多个参数

图6.png

Groovy里面,使用IO操作,即使代码出现异常,IO读取流也会保证会被关闭。比如

def count = 0, MAXSIZE = 3
new File(baseDir,"haiku.txt").withReader { reader ->
    while (reader.readLine()) {
        if (++count > MAXSIZE) {
            throw new RuntimeException('Haiku should only have 3 verses')
        }
    }
}
  • 写文件
new File('E:/Android/Groovy/workspace','write.txt') << '''Groovy is Good,
Groovy is Nice
Groovy is Beautiful!'''

在相应的位置就可以找到write.txt,然后内容为

Groovy is Good,
Groovy is Nice
Groovy is Beautiful!
集合
List操作
  • 取元素
    def emptyList = []//空List
    def list = [1,5,7,8]
    list.get[2] = 7
    list.getAt(2) = 7
    list[2] = 7
    list[-2] = 7
    list[1..2] = [5,7]
    list[1..<7] = [5,7]
  • 迭代元素
list.each{
      println "Item: $it"
}
list.eachWithIndex{
      item,i ->
      println "$i:$item"
}

Groovy映射功能,通过collect从当前集合映射到另个集合

def list = [1,5,7,8]
def newList = list.collect{it.multiply(2)}.eachWithIndex{
    item,i ->
    println "$i:$item"
}

输出

0:2
1:10
2:14
3:16
  • 过滤和搜索

list.find{it>5} == 7
list.findAll{it>5} == [7,8]

通过一个list去搜索匹配

['a','b','c','d','e'].findIndexOf{
    it in ['k','e','g']
} == 4

['a','b','c','d','e'].indexOf('c') == 2
['a', 'b', 'c', 'd', 'c'].indexOf('k') == -1//list不存在元素则返回-1
['a', 'b', 'c', 'd', 'd'].lastIndexOf('c') == 4
[1, 6, 3].every { it < 5 } == false//集合所有元素小于5则返回true
[1, 2, 4].any { it > 3 } //集合任何一个元素大于3则返回true
[1, 2, 3, 4, 5, 6].sum() == 21//求和
[1, 2, 3].join('-') == '1-2-3'//加入间隔符并转换为String

[1, 2, 4].inject(3){
    count ,item -> count + item    
} == 10 // 注入对应的元素 3+1+2+4

[1, 2, 3].max() = 3
[1,2,3].min() = 1
- 添加和删除元素

[1, 2, 4] << 5 == [1,2,4,5]
[1, 2, 4] << 5 << 7 << 8 == [1, 2, 4, 5, 7, 8]
[1, 2, 4] << [5,8] == [1, 2, 4, [5, 8]]
[1, 2] + 3 + [4, 5] + 6 == [1, 2, 3, 4, 5, 6]
[1, [2, 3, [4, 5], 6], 7, [8, 9]].flatten() == [1, 2, 3, 4, 5, 6, 7, 8, 9]
['a','b','c','b','b'] - 'c' == ['a','b','b','b']
- 排序
[6, 3, 9, 2, 7, 1, 5].sort() == [1, 2, 3, 5, 6, 7, 9]
- 复制元素
[1, 2, 3] * 3 == [1, 2, 3, 1, 2, 3, 1, 2, 3]
[1, 2, 3].multiply(2) == [1, 2, 3, 1, 2, 3]
Collections.nCopies(3, 'b') == ['b', 'b', 'b']

Map操作

其中Map操作和List操作的方法差不多,只不过Map是通过获取key来操作的,而List是通过index获取,这点和Java里面的集合操作是一样的

def map  = [Name:'Goach',Sex:'man',Age:'24',]
map.each{
    entry -> println "key:$entry.key   value:$entry.value"
}
map.eachWithIndex{
    entry ,i -> println "$i - key:$entry.key  value:$entry.value"
}
map.each{
    key,value ->  println "key:$key   value:$value"
}
map.eachWithIndex{
    key,value,i ->  println "$i -key:$key   value:$value"
}
ConfigSlurper

ConfigSlurperGroovy里面一个读取配置文件的帮助类,和Java *.properties一样。ConfigSlurper允许使用.或者以闭包的形式配置值得作用域和任意的对象类型,比如

def config = new ConfigSlurper().parse('''
        //.的形式
        app.date = new Date()
        app.sex = 'm'
      //闭包的形式 
        app {
             age = '23'
             name = 'Goach' 
         }
''')
println "date:$config.app.date; sex:$config.app.sex;"+
         "age:$config.app.age;  name:$config.app.name"

输出为:

date:Thu Jun 08 14:15:33 CST 2017; sex:m;age:23;  name:Goach

上面的的字符串我们也可以用文件形式读取,比如

def config = new ConfigSlurper().parse(new File("config.groovy").text)

MOP

Groovy也具有元对象协议的特性(Meta Object Protocol,MOP),实现这个特性,有个很重要的类就是groovy.lang.GroovyObject。基本上Groovy的对象都直接或者间接的实现了它。GroovyObject有两个很重要的方法invokeMethod()getProperty(),当一个对象调用一个方法或者属性的时候,而这个方法或者属性不存在的时候,这两个方法就会被调用。比如

class Person{
    def invokeMethod(String method,Object params){
        println "call invokeMethod ${method}"
        if(params != null){
            params.each{
                println "\tparams ${it}"
            }
        }
    }
    def getProperty(String property){
        println "property:${property}"
    }
}
def person = new Person()
person.sayHello("hello")
person.name

输出为

call invokeMethod sayHello
    params hello
property:name

当这个方法不存在的时候,它就会进行拦截,然后智能的输出响应的对象。同时会调用methodMissing这个方法

  • 添加方法
    当为一个类添加方法的时候,一般可以使用<<或者=运算符来添加方法,比如
class Car{
    String name
}
Car.metaClass.run << { -> println "$name在路上跑"}

def car = new Car(name:"宝马")

car.run() == "宝马在路上跑"
  • 添加属性
Car.metaClass.speed = '120km/h'
  • 构造函数
class Food{
    String name
}
Food.metaClass.constructor << { String name -> new Food(name:name)}

def food = new Food('apple')

println "food name is ${food.name}"
  • 静态方法
class Book {
   String title
}

Book.metaClass.static.create << { String title -> new Book(title:title) }

def b = Book.create("The Stand")
  • 间接调用方法
class Person{
    String name
}
class Action{
    def sayHello(){
        "Hello!"
    }
}
def action = new Action()
Person.metaClass.hello = action.&sayHello
def person = new Person()
println person.hello() == "Hello!"
  • 动态方法名称
class Person{
    String name = "Goach"
}
def methodName = "Lili"

Person.metaClass."changeNameTo${methodName}" = {-> delegate.name = "Lili"}

def person = new Person()
println person.changeNameToLili() == "Lili"

Groovy更多的使用方法,例如AST转换,Grape的依赖,写一些测试用例,DSL语言以及GroovyJava里面的常用方法可以参考官网,由于篇幅的原因,入门的简单学习就暂时到此为止。

参考文献

Groovy官网
Groovy1.6的新特性
Groovy入门
实战Groovy

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值