️This article has been over 2 years since the last update.
其实这本书早就买了,本来是作为字典查知识点的,现在又读了一遍。使用Groovy已经有了接近一年的时间,再读一遍。本文就是一些总结。
1. Groovy学习路线
Groovy在网上还是比较冷,如果读者不喜欢Groovy,项目没有使用或者对DSL没有兴趣的话,可以去试一下kotlin
1.1. 学习流程
- 直接找一本书开始看,比如本文的书
- 看了一半,使用GroovyConsole工具去实验
- 使用Groovy代替Java去写部分代码
- 最终重构Java代码,它将有强烈的Groovy风格
1.2. 学习工具建议
- 使用Idea作为开发工具,它可以实现类型推导,并且反编译看Groovyc生成的Java也非常方便
- 特别推荐使用调试时的
Code Fragment
- 加入
CompileStatic
注解,实现了Groovy静态化,方便对比编译结果
2. Groovy部分知识点
由于学的语言比较多,因此只说下Groovy的重点特性
2.1. 操作符重载
默认的各种重载通过DefaultGroovyMethods
实现,这个C++,Scala等语言也是支持的。工具类代码难度不高,可读性也没问题,类似于Guava。
2.1.1. boolean值重载: asBoolean()
测试代码如下
1 | def a = [] |
可以发现它的调用栈是如下的,也就是说,在Groovy中,if要求返回值必须为boolean,所有数据最终都会调用asBoolean()
1 | org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean(DefaultGroovyMethods.java:10390) |
因此在Groovy中,不需要写if(s== null || s.isEmpty())
这样的代码,而是直接用if(s)
即可
这里有个坑,比如if(0)就返回了false,而很多时候
0
是有意义的,导致费用等业务出现逻辑错误。
2.1.2. +
重载: plus()
这个API过于灵巧了,比如List相加的时候。我个人建议用plus
代替+
,因为时间久了这些语法糖可能会忘记
你可以借助IDE的类型推导,按住Ctrl点击代码的加号,就可以进入相应的源码中
2.1.3. 其它操作符重载
这些用的不多,自己点进去看吧
- forIn重载: next()
<<
重载: leftShift()- a[‘b’]属性获取: a.getAt(‘b’)
2.2. 集合类
Groovy的集合类API几乎没有任何门槛,比如each, find, collect 等,这种API一次学习,各个平台都可以使用。实现类同样在DefaultGroovyMethods
中,这些API必须精通至少一个平台
这类代码都推荐看,类似还有Java8的Stream, Google的Guava, 都是惰性求值。有了此类代码的思路,以后遇到新语言直接看DOC即可。
2.3. 使用Groovy设计DSL
DSL是领域专属语言,使用Groovy开发DSL有如下优点
- 相对应Java,性能差距并不是非常大,同样享受到了JVM红利,并且也支持静态编译。
- 相对应XML等外部DSL,信息量比标记语言更大(想想ant与gradle的区别),而且它的methodInvoking机制非常方便定制
- 相比于自己折腾一个新语言,它不用实现复杂的Parser与断点/IDE,避免了内部派系之争
举个例子,有的老项目采用了ant脚本进行打包,调试费力不说,跨平台换个jar包也一堆问题,这时我们可以用Groovy+Jenkens去代替它
比如配置一个maven任务,可以是下面这样的,源码见这里
1 | mavenJob('example') { |
如果你熟悉Jenkins,那么上面的代码几乎可以秒懂,甚至一个Groovy外行也可以修改定制。
单行代码中的信息量表达能力越高,它越仅适用于某些特定业务——它背后的解释器专为这些语法进行定制。
2.3.1. Closure、Lambda and Functional Programming
闭包是短小的、轻量的匿名函数,在动态语言中使用非常广泛。它最开始从函数式编程的Lambda表达式中派生,指定了一个函数的参数与映射,并加入了语法糖。在实际开发中,闭包一般用于
- 封装业务无关的样板代码(比如资源清理,网络连接、简化循环),值得注意的是,闭包多作为参数传入函数,而工具类是作为主动方去调用的。使用Groovy的Category可以无侵入使用Java之前的工具类
- 创建内部DSL,比如Groovy的XmlMarkup
2.3.2. 闭包与函数的区别
- 函数入参可以把闭包代码段作为入参传入
- 闭包是匿名函数。函数用于解决特定领域问题,闭包着重于解决通用领域问题
- 函数与闭包内部都尽量避免与外界接触,最好是“无状态”的,比如Java的匿名内部类就强制外部变量为
final