groovy in action

来源:互联网 发布:mac修改终端用户名 编辑:程序博客网 时间:2024/05/22 07:03

在JVM中运行groovy类有两种方式:

 使用groovyc编译所有的*.groovy为java的*.class文件,把这些*.class文件放在java类路径中,通过java类加载器来加载这些类。

 通过groovy的类加载器在运行时直接加载*.groovy文件并且生成对象,在这种方式下,没有生成任何*.class,但是生成了一个java.lang.Class对象的实例。(java的动态编译加载功能)

groovy在源代码级增强java,但是在字节码是与java一样的




Groovy的语法是面向行的,但是执行groovy代码却不是这样的,不像别的脚本语言,groovy代码不是一行一行的解释执行的。

groovy代码被完整地转换,通过转换器产生一个java类,产生的这个类是groovy和java之间的粘合剂。产生的groovy类的格式与java字节码的格式是一样的。

groovy的类加载器能够从*.groovy文件加载类(在放入缓存之前进行转换和生成类)。



在运行时生成groovy类

1.MyScript.groovy被传递给groovy的转换器

2.转换器产生一个抽象语法树(AST)来表示在MyScript.groovy中的所有代码;

3.Groovy类生成器根据AST产生java字节码,根据脚本的内容,结果可能是多个类,现在类通过groovy类加载器是可以使用的了;

4.Java运行时像调用一个java类MyScript一样来调用第三步产生的类;


在使用之前类已经完整地构建并且在运行时不能进行更改(不排除在.groovy被修改之后对类在运行时的替换)。



groovy中一切事情都是对象,所有的操作符都是作为方法调用进行处理的。



注意BigDecimal是默认的非整数类型——除非指定后缀强制类型为Float或者Double,否则将使用BigDecimal。




给定期望信息的时候groovy是如何处理类型的:

在groovy中出现的字面符号(数字、字符串等等)没有任何问题,它们都是对象,它们仅仅传递给java时才进行装箱和拆箱,操作符是方法调用的快速途径。



操作符是方法的便利写法(在groovy中所有的都是对象,操作符是对象方法的便利写法):


“==”或者equals指示对象是否同等(值相等),而不是是否指向同一个对象。

实现equals的目的是保证这个对象可以与null对象进行对比。equals操作的缺省实现是不抛出NullPointerException。



times方法仅仅用于做重复的动作,upto方法是递增一个数字,downto是递减一个数字,step是按一个步进从一个数递增到另外一个数。



在面向对象语言,方法对象模式(Method-Object-pattern)通常用来模拟一个行为:为一个目的定义一个独立的方法接口,这个接口的实例能够传递一组参数给方法,然后调用这个接口方法。


一个闭包是一个用花括号围起来的语句块,为了传递参数给闭包,闭包有一组可选的参数列表,通过“->”表示列表的结束。




脚本允许使用没有声明的变量,在这种情况下变量被假定从脚本的binding属性获取,如果在binding中没有发现相应的变量,那么把变量增加到bindding中,binding是一个数据存储器,它能把变量在脚本调用者和脚本之间进行传递。


缺省属性范围在groovy有特殊的意思,在没有指定范围修饰符的属性声明的时候,groovy会根据需要生成相应的访问方法(getter方法和setter方法)


定义变量的类型是可选的,不管怎样,标示符在声明的时候不必独一无二,当没有类型和修饰符时,必须使用def来作为替换,实际上用def来表明属性或者变量是没有类型的(尽管在内部将被声明为Object类型)。





重写下标操作符:

  重写get方法意味着重写了dot-fieldName操作符,重写了set方法意味着重写了field assignment操作符。



class PretendFieldCounter{public count = 0;Object get(String name){return 'pretend value';}void set(String name,Object value){count++}}class Test {static main(args) {def pretender = new PretendFieldCounter();println pretender.isNoField == 'pretend value';println pretender.count == 0;pretender.isNoFieldEither = 'just to increase counter'println pretender.count == 1}}

结果全都是true



第五章闭包

一个闭包是被包装为一个对象的代码块,实际上闭包像一个可以接受参数并且能够有返回值的方法。

闭包是一个普通对象。


闭包的简短写法:

原本:
class Closure {static main(args) {Closure envelope = {person-> printf(person)}["a","b"].each(envelope);}}

可以写成如下形式:
class Closure2 {static main(args) {["a","b"].each{printf(it)};}}

使用闭包作为单个参数的方法调用(在groovy中传递一个闭包给一个方法是非常平常,没有特殊规则。)
如果闭包仅仅需要一个参数,groovy提供了一个缺省的名称——it


声明闭包

在一个方法调用的后面,放置闭包代码在一对花括号里,闭包的参数和代码通过箭头(->)进行分隔。

第二种声明闭包的方式是直接将它赋给一个变量:
def printer = {line -> println line}

通过方法的返回值
def Closure getPrinter(){return {line -> println line}}

花括号指明构建了一个新的闭包对象

提示:或括号能用来标明构建了一个新的闭包对象或者一个groovy代码块,代码块可以是类、接口、static、对象的初始化代码、方法体,或者与groovy的关键字(if、else、synchronzied、 for、 while、 switch、 try、 catch和finally)一起出现,其他出现的形式就是闭包。

第三种声明闭包的方式是重用已有的声明:一个方法。

方法闭包被限制在一个实例方法,但是可以实现运行时重载。


如果闭包的参数进行了显示的类型声明,那么类型的检查发生在运行时而不是在编译的时候


调用闭包:

一个引用x指向一个闭包,可以通过x.call()来调用闭包或者简单的x()

class CallingClosures {static main(args) {def adder = {x,y -> return x+y}assert adder(4,3) == 7assert adder.call(2,6) == 8}}


有缺省值的闭包:
class Closure4 {static main(args) {def adder = {x,y=5 -> return x+y}assert adder(4,3) == 7assert adder.call(7) ==12}}

闭包典型的调用方式:




闭包参数的数量:
class Closure5 {def caller(def closure){closure.getParameterTypes().size()}void test(){assert caller{ one ->}  ==1assert caller{ one,two ->}  ==2}static main(args) {new Closure5().test()}}

curry函数(函数式编程)
class Closure6 {static main(args) {def configurator = { format,filter,line->filter(line)? format(line):null}def appender = {config,append,line ->def out = config(line)if(out) append(out)}def dateFormatter = {line -> "${new Date()}:$line"}def debugFilter = { line -> line.contains('debug')}def consoleAppender = { line -> println line}def myConf = configurator.curry(dateFormatter,debugFilter)def myLog = appender.curry(myConf,consoleAppender)myLog('here is some debug message')myLog('this will not be printed')}}

通过isCase方法进行分类
class Closure7 {static main(args) {assert [1,2,3].grep{ it < 3} == [1,2]switch(10){case {it%2 == 1} : assert false}}}

花括号显示了闭包声明的时间,不是执行的时间