- java.lang
- java.util
- java.io
- java.net
- java.math.BigDecimal
- java.math.BigInteger
- groovy.lang
- groovy.util
return语句几乎总是可选的- 尽管可以使用分号分隔语句,但它几乎总是可选的
- 方法和类默认是
public的 ?.操作符只有对象引用不为空时才会分派调用- 可以使用具名参数初始化
JavaBean Groovy不强迫我们捕获自己不关心的异常,这些异常会被传递给代码的调用者静态方法内可以使用this来引用CLass对象
groovy 自动创建 getter setter
groovy 默认public 且不区分 public private protected
groovyc会忽略@Override
| 类型 | 为true条件 |
|---|---|
| Boolean | 值为true |
| Collection | 集合不为空 |
| Character | 值不为0 |
| CharSequence | 长度大于0 |
| Enumeration | hasMoreElements() 为 true |
| Iterator | hasNext() 为true |
| Number | Double值不为0 |
| Map | 该映射不为空 |
| Matcher | 至少有一个匹配 |
| Object[] | 长度大于0 |
| 其他任何类型 | 引用不为null |
groovy ==
Groovy 的 == 映射到 equals() 方法
当实现 Comparable 接口时 会将 == 映射到 compareTo() 方法
groovy 的 is() 是 比较 内存地址类型检查默认关闭
groovy 中 x=y 在语义上等价于 x=(ClassOfx)y 强制类型转换
groovy编译器不会验证类型,只是进行强制类型转换,然后将其留给运行时处理 可能出现 GroovyCastException 异常
通过 javap -c CLassFileName 分析字节码验证上述内容
如果调用一个不存在的方法,也不会出现编译错误,运行时会出现 MissingMethodException
利用上诉内容,可以在代码编译时和执行时动态注入缺失的方法
groovy 方法内不能有任何代码块 如下
java的代码块,groovy编译器会错误地认为要定义一个闭包,并给出编译错误
public void method()
{
System.out.println("hello");
//groovy编译器会错误地认为 下面的代码块 是要定义一个闭包,并给出编译错误
{
System.out.println("hello");
}
}
def用于定义方法,属性,局部变量
in用于在for循环中指定循环的区间
it虽然不是关键字,但是 闭包内默认使用此变量名
动态类型语言中的类型是在运行时推断的
方法及其实参也是在运行时检查
通过这种能力可以在运行时向类中注入行为,从而使代码比严格的静态类型具有更好的扩展性借助动态类型,可以用比Java更少的代码创建灵活的设计
将实参的类型验证推迟到运行时这一特性为Groovy中的多态注入了活力
利用多方法(multimethods)这一工具,可以为与实参的运行时类型相关的操作提供替换行为
闭包三属性 this owner delegate 参考:ThisOwnerDelegate.groovy
用于确定哪个对象处理该闭包内的方法调用
闭包内引用的变量和方法都会绑定到 this
this负责处理任何方法调用,以及任何属性和变量的访问
如果 this 无法处理,则转向 owner 最后是 delegate
- this 上下文 脚本实例
- owner
- delegate
- delegate 会设置为 owner
- with函数会修改 delegate 以执行动态路由
在groovy代码中使用groovy类,无需额外操作,直接可以工作
需要确保所依赖的类在类路径 classpath 下;是字节码、源代码
java类中使用groovy脚本
JSR 223 提供的 ScriptEngine API
Java中使用groovy类 或者 groovy中使用java类
利用groovy 联合编译工具(joint-compilation)
带有附加功能的Java对象
Groovy使用的三类对象:POJO (plain old java object 普通java对象)扩展了java.lang.Object
POGO (plain old groovy object 普通groovy对象) 扩展了java.lang.Object 同时实现了groovy.lang.GroovyObject
Groovy 拦截器,扩展了 GroovyInterceptable 的groovy对象,具有方法拦截功能
invokeMethod()、getProperty()、setProperty()使Java对象具有高度动态性,可以使用他们来处理运行中创建的方法和属性
getMetaClass()、setMetaClass() 使创建代理拦截POGO上的方法调用、在POGO上注入方法变得非常容易
一旦一个类被加载到JVM中,就不能修改它的元对象Class,可以通过setMetaClass() 修改它的MetaClass,好像对象在运行时修改了它的类
package groovy.lang;
import groovy.transform.Internal;
public interface GroovyObject {
/**
* Invokes the given method.
*
* @param name the name of the method to call
* @param args the arguments to use for the method call
* @return the result of invoking the method
*/
@Internal
// marked as internal just for backward compatibility, e.g. AbstractCallSite.createGroovyObjectGetPropertySite will check `isMarkedInternal`
default Object invokeMethod(String name, Object args) {
return getMetaClass().invokeMethod(this, name, args);
}
/**
* Retrieves a property value.
*
* @param propertyName the name of the property of interest
* @return the given property
*/
@Internal
// marked as internal just for backward compatibility, e.g. AbstractCallSite.createGroovyObjectGetPropertySite will check `isMarkedInternal`
default Object getProperty(String propertyName) {
return getMetaClass().getProperty(this, propertyName);
}
/**
* Sets the given property to the new value.
*
* @param propertyName the name of the property of interest
* @param newValue the new value for the property
*/
@Internal
// marked as internal just for backward compatibility, e.g. AbstractCallSite.createGroovyObjectGetPropertySite will check `isMarkedInternal`
default void setProperty(String propertyName, Object newValue) {
getMetaClass().setProperty(this, propertyName, newValue);
}
/**
* Returns the metaclass for a given class.
*
* @return the metaClass of this instance
*/
MetaClass getMetaClass();
/**
* Allows the MetaClass to be replaced with a derived implementation.
*
* @param metaClass the new metaclass
*/
void setMetaClass(MetaClass metaClass);
}
扩展了GroovyObject的标记接口,对于实现了该接口的对象而言,其上所有方法调用,不管是否存在,都会被invokeMethod() 方法拦截
package groovy.lang;
/**
* Marker interface used to notify that all methods should be intercepted through the <code>invokeMethod</code> mechanism
* of <code>GroovyObject</code>.
*/
public interface GroovyInterceptable extends GroovyObject {
}当调用一个方法时Groovy会检查目标对象时一个POJO还是POGO,不同类型,groovy方法处理不同
对于POJO Groovy 维护了MetaClass的一个 MetaClassRegistry调用方法时,Groovy 会去应用类的 MetaClassRegistry 取它的MetaClass,将方法调用委托给它
因此在它的MetaClass上定义的任何拦截器或方法,都优先于 POJO原来的方法对于POGO POGO有一个到其MetaClass的直接引用
POGO 调用方法时,groovy 会采取一些额外的步骤,如下图:
如果对象实现了GroovyInterceptable,那么所有的调用都会被路由到它的invokeMethod(),在此拦截器内,可以再把调用路由给实际的方法,使类AOP的操作成为可能
如果对象未实现GroovyInterceptable,会先查找其MetaClass中的方法如果没有则查找POGO自身上的方法,如果该POGO没有这样的方法,Groovy会以方法名查找属性或字段
如果属性或字段使Closure类型的(闭包),Groovy会调用它,代替方法调用
如果没有找到这样的属性或字段,会做最后两次尝试如果POGO有一个名为methodMissing()的方法,则调用该方法
否则调用POGO的invokeMethod()如果POGO实现了invokeMethod(),会被调用
invokeMethod()默认实现会抛出 MissingMethodException异常,说明调用失败
groovy.lang.ExpandoMetaClass 是 MetaClass 接口的众多不同实现之一
默认情况下 groovy 目前并没有使用 groovy.lang.ExpandoMetaClass
当我们向 metaClass 添加一个方法时,默认的 metaClass 会被用一个 groovy.lang.ExpandoMetaClass 实例替换掉
eg
- Groovy 的 MOP 支持以下3种技术注入行为种的任何一种
- 分类category
- ExpandoMetaClass
- Mixin
与某些只有运行时能力的动态类型语言不同,groovy同时提供了运行时和编译时元编程
将与类和实例上方法的拦截、注入甚至合成相关的决策推迟到运行时。就元编程而言,这些就够了
编译时元编程时一种高级特性,主要是框架或工具的编写者使用
借助Groovy可以在编译时分析和修改程序的结构。可以为应用带来高度的可扩展性
同时支持添加新的横切特性无需修改源代码,即可为线程安全、日志消息和在代码的不同部分执行前置和后置的检验操作等,对类进行检查
canVote() 方法很短,只是返回三元操作符的结果,但是其AST却异常丰富,包含很多细粒度的细节信息(参见下图)
groovy 编译器允许我们进入其编译阶段,一窥其所处理的AST(抽象语法树)
AST描述了程序中的表达式和语句,使用节点表示
随着编译过程的进行,AST会被变换,包括节点的插入、删除和重新排列
在编译过程中,可以随着AST的演进对他进行检查,以及命令编译器去标记警告或错误
通过 extends 重写方法 模拟 groovy 和 java 代码,使用现有的单元测试和模拟框架来测试
对 groovy 代码进行单元测试,可以使用分类和ExpandoMetaClass。 二者都支持通过拦截方法调用,实现模拟。
如果使用 ExpandoMetaClass 不必创建额外的类,测试会很简洁对与参数对象的简单模拟可以使用 Map 或 Expando
如果想对多个方法设置测试预期,以及想模拟被测方法内部的依赖,可以使用 StubFor
要测试状态以及行为,可以使用MockFor
特点:
上下文驱动
语境 生命周期
非常流畅
改进代码的可读性,同时使代码自然地流动
要在设计上实现流畅并不容易,应该让用户使用起来很流畅DSL 针对的是“某一特定类型的问题”。其语法聚焦于指定的领域或问题。
不会像使用 Java、Groovy或C++等语言那样将其应用于一般性编程任务,因为DSL的应用领域和能力都非常有限。
必须确定要设计 外部 DSL 还是 内部 DSL
外部DSL 例如:Ant 使用的是XML,是外部 DSL
外部DSL 定义了一门新语言。
可以灵活地选择语法,之后是解析新语言中的命令并执行动作
解析 DSL 可以使用诸如 C++ 和 Java 等语言,使用它们提供的解析功能及库,
以及利用他们提供大量解析功能和库来处理繁重的任务内部DSL 例如 Gant 使用 Groovy 来解决 Ant 同样的问题,但它是内部 DSL
也称做嵌入式 DSL 同样定义了一门语言,但是语法受到现有语言的约束
不必使用任何解析器,但必须巧妙地将语法映射到底层语言中的方法和属性等构造。
内部 DSL 用户可能意识不到自己正在使用的是一门更广的语言的语法。
为了让底层语言工作,创建内部 DSL 需要在设计上付出巨大的努力,而且还需要一些聪明的技巧。设计内部 DSL
动态语言很适合设计和实现内部的 DSL。
这些语言提供了很好的 元编程能力 和 灵活的语法,便于轻松地加载和执行代码片段
并非所有的动态语言都是一样的。
如 Ruby 动态类型、括号可选、可以用冒号代替双引号引用字符串,等等。 为创建内部 DSL 提供极大支持
如 Python 中空白是有意义的,可能会成为创建 DSL 的障碍
Groovy 的动态类型和元编程能力对于创建内部的 DSL 帮助很大。
但是groovy 对括号的处理,以及它没有 Ruby 提供的优雅的冒号符号,都会有一些限制。
- 动态类型与可选类型
- 动态加载、操纵和执行脚本的灵活性
- 分类和 ExpandoMetaClass 可以打开类
- 闭包为执行提供了很好的上下文
- 操作符重载有助于自由地定义操作符
- 生成器支持
- 灵活的括号
- 调用需要参数的方法时,不要求括号
- 调用没有参数的方法时,必须带括号



