groovy心得

hello world

传统的类+static main函数的方式:

class Car {
    static main(args){
        println 'hello world'
    }
}

也可以直接这么写:

println 'hello world1'

基本语法

函数最后一行作为返回值、返回多值

def split(String s) {
    s.split(",")
}

def (a, b) = split("julia,coca,python")
println "$a $b"

输出:

julia coca

最后一个值python被丢弃了。

bool求值

groovy行为类似于python而非java,下面的例子给出了值判空、集合判空的例子:

def l = [1,2], l1 = []
if(l){
    println("collection NOT empty")
}
if(!l1){
    println("collection IS empty")
}

def (c,d) = [1,0]
if(c){
    println('value NOT zero')
}
if(!d){
    println('value zero')
}

说明:

值为null也会被判定为false

这个类C语言的特性比java方便多了。

字符串

字符串的用法也跟python很像,单引号、双引号括起来皆可,多行字符串用三引号表示:

a = 'julia'
s = """introduce
i am a teacher $a
"""
println s

s = 'tutu $a'
println(s)

s = "tutu $a"
println s

注意:

双引号会执行其中的$表达式(术语叫字符串插值),单引号则不会

当然,python可没有字符串插值的能力,scala倒是有:

val a = "julia"
println(s"tutu $a")

在scala里除了s插值,还有f插值、raw插值,具体可参考相关资料。

集合

列表

l = [1,2]
for(i in l){
    println i
}
println(l[1])
println(l[-1])
l.add(3)
l << 4
println l

演示了:

  • 列表定义
  • 遍历
  • 下标访问(注意:负下标也是有效的)
  • 尾部添加

行为上跟python的list几乎是一样的

字典

m = ['china':1, 'usa':2]
m.each { k,v ->
    println "$k=>$v"
}
println m['china']
m.put('russia',3)
println m

演示了:

  • 字典定义,跟python有点区别,使用[],而非{}
  • 遍历
  • 下标访问
  • 添加元素

遍历方法跟scala很像,scala里字典遍历的写法是这样:

val m = Map(1 -> "dudu", 2 -> "haha")
m.foreach{case (k,v) => println(s"$k=>$v")}

这里case语句作为一个偏函数传入foreach。

groovy下each传入的则是一个闭包(或称之为代码块)。

闭包

groovy里的闭包其实是匿名函数,严格的说,只有捕获了外部变量的匿名函数,才算闭包,所以groovy使用闭包这个术语不太严谨。

我们令pickEven函数可以接收一个闭包block:

def pickEven(n, block){
    for(i=0; i<=n; i+=2){
        block(i)
    }

}

在groovy里有两种调用方式:

//普通调用
pickEven(10, {i -> println(i)})
//curry化调用
pickEven(10){
    i -> println(i)
}

看一下对应的scala的例子:

def pickEven(n:Int, block: Int => Unit): Unit ={
    0.to(n, 2).foreach(block)
}
//普通调用
pickEven(10, x => println(x))  


def pickEven1(n:Int)(block: Int => Unit): Unit ={
    0.to(n, 2).foreach(block)
  }
//curry化调用
pickEven1(10){
      (x:Int) => println(x)
    }

可见,groovy里的闭包等价于scala或java里的lambda。区别仅在于:

  • groovy的闭包必须用{}括起来,而scala则不必
  • groovy闭包的curry化调用更方便,无需额外定义函数的curry化版本

当然,不论groovy的闭包还是scala的lambda,都具备访问外部变量的能力。

groovy下闭包访问外部变量total:

total = 0
pickEven(10){
    total += it
}
println("total $total")

对应的,scala下lambda访问外部变量total:

var total = 0
pickEven1(10){
  x => total += x
}
println(s"total $total")

另外,groovy闭包的curry化调用很适合用作资源清理自动化,在scala里也有类似的技巧。

java调用groovy

java调用groovy有两种方式,一是静态调用,二是动态调用。

静态调用

先定义一个groovy类:

class Car {
    def miles = 0
    final year

    Car(theYear){
        year = theYear
    }
}

接着在java里直接访问:

    private static void testGroovy()
    {
        Car c  = new Car(1980);
        System.out.println(c.getMiles());
        System.out.println(c.getYear());
    }

groovy会为def声明的成员变量自动生成get、set方法,所以对Car.miles的访问变成c.getMiles()。

动态调用

动态调用要通过ScriptEngine:

private static void testScriptEngine() throws ScriptException, IOException {
        ScriptEngineManager manager = new ScriptEngineManager();

        ScriptEngine se = manager.getEngineByName("groovy");
        Object res = se.eval("1+1");
        System.out.println(res.toString());

        String path = "src/main/resources/hello.groovy";
        try(FileReader fr = new FileReader(path))
        {
            se.eval(fr);    
        }

    }

hello.groovy脚本的内容:

println 1+4
println('hello world')

import com.isearch.study.*
def son = new Son()
son.doSth()

执行结果:

2
5
hello world
Son doSth

我们发现,java作为宿主调用groovy脚本后,在groovy脚本中还可以再反向调用java中的类Son。这是因为groovy classloader的父亲就是application classloader,根据双亲委派原则,最终还是会由application classloader来负责加载java类。

双亲委派原则

如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。

如果类Son不存在,一般会报错:

catch exception:org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script2.groovy: 5: unable to resolve class Son1 
 @ line 5, column 11.
   def son = new Son1()
             ^

1 error

实际中,如果出现“unable to resolve class”的错误,往往是类加载器体系出了问题。

groovy调用java

groovy可以无缝的访问java类

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值