定义Map
def map1 = [
keyToStr : "value",
keyToVar : varRef,
keyToList : [e1, e2, e3],
keyToMap : [
key1 : 1,
key2 : 2,
key3 : 3
],
(XxxClass.simpleName) : "xxx" // Expression as Key
]
groovysh
// groovysh 使用 untyped 类型。而使用 def 或 明确类型的 变量,将不会暴露到 shell 环境中。
// 可以通过以下方式改变
:set interpreterMode
// 列出所有本机IP地址。
Enumeration e = NetworkInterface.getNetworkInterfaces();
while(e.hasMoreElements())
{
NetworkInterface n = (NetworkInterface) e.nextElement();
Enumeration ee = n.getInetAddresses();
while (ee.hasMoreElements())
{
InetAddress i = (InetAddress) ee.nextElement();
if(i.isAnyLocalAddress() || i.isLoopbackAddress() || i.isMulticastAddress() || i.getAddress().length != 4){
continue;
}
System.out.println(i.getHostAddress());
}
}
Design patterns in Groovy
see here
DSL
空格用来分隔方法调用,如果没有参数,则需要明确加上
()
// equivalent to: turn(left).then(right) turn left then right // equivalent to: select(all).unique().from(names) select all unique() from names
逗号用来分隔单个方法调用时的参数列表
// equivalent to: paint(wall).with(red, green).and(yellow) paint wall with red, green and yellow // with named parameters too // equivalent to: check(that: margarita).tastes(good) check that: margarita tastes good
注解中无法使用常量
see groovy issue 2178. 只能先在Java中定义常量,再在groovy中引用。
添加新方法
为类添加静态方法
- ExpandoMetaClass
- MetaClasses
- Per-Instance MetaClass
- Understanding Groovy/Grails classloader leak
- Difference between @Delegate, @Mixin and Traits in Groovy?
- Metaclass methods protecte objects from gc, is this a bug?
- MetaClass gc'ing
per-Instance 与 其 metaClass 存储在 org.codehaus.groovy.reflection.ClassInfo#perInstanceMetaClassMap 中,参见348行。
Object.metaClass.static.hi = {println "hi,"+it}
Object.metaClass.static.hi = {String str-> println "hi-" + str}
Object.metaClass.static.getMyClassName = { delegate.name }
Integer.hi() // 无参函数
Integer.hi("a") // 含参函数
println Integer.myClassName // java.lang.Integer
为类添加预定义的新方法、属性
// 追加方法
Object.metaClass.hi = {println "hi,"+it}
Object.metaClass.hi = {String str-> println "hi-" + str}
// 追加属性:命名要求是 getXxx
Object.metaClass.getMyClassName { delegate.getClass().getName() }
1.hi() // 无参函数
1.hi("a") // 含参函数
println 1.myClassName
为类添加动态发现的新方法、属性
TODO
为特定的实例添加方法
def a = "a"
def b = "b"
a.metaClass.hi{println "hi,$delegate"}
a.hi()
b.hi() // ERROR
为特定的实例添加新属性
TODO
FIXME
// export JAVA_OPTS="-Xmx12M -XX:-UseGCOverheadLimit -Xloggc:gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=oom.dump.hprof"
// 1. 限定最大堆内存大小,
// 2. 不抛出 java.lang.OutOfMemoryError: GC overhead limit exceeded
// 3. 记录gc日志
// 4. 内存溢出时,dump出内存
// groovy GMain.groovy
// 该测试用例大约在 250 次的时候出错
class GMain {
static main(args) {
def r = new Random()
500.times { i ->
def str = r.nextInt().toString()
def list = []
10.times {
list << r.nextInt()
}
str.metaClass.bbb = {list}
println "${i} : ${str}.bbb = ${str.bbb()}"
}
}
}
自定义 AST
参考: Developing AST transformations
全局 transformation
当代码编译时记性,参与全局变换的,需要在相应的jar包中
META-INF/services/org.codehaus.groovy.transform.ASTTransformation
进行配置。实现类必须实现 org.codehaus.groovy.transform.ASTTransformation 接口并提供无参数构造函数。
可以通过 ASTTransformationCustomizer 配置,可以避免将 自定义筛选用的 annotation 类放到单独的一个jar包中。
本地 transformation
必须在 org.codehaus.groovy.control.CompilePhase 中定义的9个阶段完成
AST 类型检查
请参考 这里
Closure#rehydrate()
、@DelegatesTo
Gradle 中相关的静态类型检查请参考
gradle-api-3.4.1.jar!/META-INF/services/org.gradle.initialization.GradleApiSpecProvider
- org.gradle.initialization.DefaultGradleApiSpecProvider
- DefaultServiceLocator
GradleApiSpecProvider
GradleApiSpecAggregator 通过 DefaultServiceLocator
GlobalScopeServices#createClassLoaderRegistry()
-> new DefaultClassLoaderRegistry()
-> GradleApiSpecAggregator#aggregate()
-> DefaultServiceLocator#implementationsOf() // 从 `META-INF/services/` 找出实现了 GradleApiSpecProvider 的服务类,
// 目前只有一个 —— DefaultGradleApiSpecProvider
-> DefaultGradleApiSpecProvider
Type checking extensions
see here
- org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport