groovy 2.5.4
新发布的Groovy 2.0通过静态类型检查和静态编译为该语言带来了关键的静态功能,采用了与JDK 7相关的改进,以及Project Coin语法增强功能和对新的“调用动态” JVM指令的支持,并且比以前更加模块化 。 在本文中,我们将更详细地研究这些新功能。
动态语言的“静态主题”
静态类型检查
Groovy本质上一直是并且将永远是一种动态语言。 但是,Groovy通常用作“ Java脚本语言”或“更好的Java”(即,具有更少样板且功能更多的Java)。
许多Java开发人员实际上使用Groovy作为扩展语言并将其嵌入Java应用程序中,以编写更具表现力的业务规则,进一步为不同客户定制应用程序等。对于此类面向Java的用例,开发人员不需要语言提供的所有动态功能,并且他们通常期望Groovy编译器提供与javac相同的反馈。 特别是,他们希望获取诸如变量或方法名称上的错字,错误的类型分配等之类的编译错误(而不是运行时错误)。 这就是Groovy 2具有静态类型检查支持的原因 。
发现明显的错别字
静态类型检查器是使用Groovy现有的强大AST(抽象语法树)转换机制构建的,但是对于不熟悉这些机制的用户,您可以将其视为通过注释触发的可选编译器插件。 作为一项可选功能,如果您不需要它,则不必强制使用它。 要触发静态类型检查,只需在方法或类上使用@TypeChecked
批注以所需的粒度级别打开检查。 让我们来看第一个示例:
import groovy.transform.TypeChecked
void someMethod() {}
@TypeChecked
void test() {
// compilation error:
// cannot find matching method sommeeMethod()
sommeeMethod()
def name = "Marion"
// compilation error:
// the variable naaammme is undeclared
println naaammme
}
我们使用@TypeChecked
注释对test()
方法进行注释,该方法指示Groovy编译器在编译时对该特定方法运行静态类型检查。 我们试图用一些明显的错别字来调用someMethod()
,并用另一种错别字再次打印名称变量,编译器将抛出两个编译错误,因为分别找不到或声明了方法和变量。
检查您的分配并返回值
静态类型检查器还验证分配的返回类型和值是否一致:
import groovy.transform.TypeChecked
@TypeChecked
Date test() {
// compilation error:
// cannot assign value of Date
// to variable of type int
int object = new Date()
String[] letters = ['a', 'b', 'c']
// compilation error:
// cannot assign value of type String
// to variable of type Date
Date aDateVariable = letters[0]
// compilation error:
// cannot return value of type String
// on method returning type Date
return "today"
}
在此示例中,编译器将抱怨您无法在int
变量中分配Date
,也不能返回String
而不是方法签名中指定的Date
值。 脚本中间的编译错误也很有趣,因为它不仅抱怨错误的分配,而且还因为它在播放时显示类型推断,因为类型检查器当然知道letters[0]
是输入String
,因为我们正在处理的数组Strings
。
有关类型推断的更多信息
由于我们提到类型推断,因此让我们看一下它的其他一些实例。 我们提到类型检查器跟踪返回类型和值:
import groovy.transform.TypeChecked
@TypeChecked
int method() {
if ( true ) {
// compilation error:
// cannot return value of type String
// on method returning type int
'String'
} else {
42
}
}
给定一个返回原始类型int
值的方法,类型检查器还可以检查从不同结构(如if / else
分支, try / catch
块或switch / case
块)返回的值。 在此,在我们的示例中, if / else
块的一个分支尝试返回String
值,而不是原始int
,编译器对此抱怨。
仍然允许普通类型转换
但是,静态类型检查器不会抱怨Groovy支持的某些自动类型转换。 例如,对于返回String, boolean
或Class
方法签名,Groovy会自动将返回值转换为以下类型:
import groovy.transform.TypeChecked
@TypeChecked
boolean booleanMethod() {
"non empty strings are evaluated to true"
}
assert booleanMethod() == true
@TypeChecked
String stringMethod() {
// StringBuilder converted to String calling toString()
new StringBuilder() << "non empty string"
}
assert stringMethod() instanceof String
@TypeChecked
Class classMethod() {
// the java.util.List class will be returned
"java.util.List"
}
assert classMethod() == List
静态类型检查器也足够聪明,可以进行类型推断 :
import groovy.transform.TypeChecked
@TypeChecked
void method() {
def name = " Guillaume "
// String type inferred (even inside GString)
println "NAME = ${name.toUpperCase()}"
// Groovy GDK method support
// (GDK operator overloading too)
println name.trim()
int [] numbers = [1, 2, 3]
// Element n is an int
for ( int n in numbers) {
println
}
}
尽管name
变量是使用def
定义的,但是类型检查器可以将其理解为String
类型。 然后,在插值的字符串中使用此变量时,它知道可以调用String's toUpperCase()
方法,或稍后调用trim()
方法,该方法是Groovy Development Kit修饰String
类的方法。 最后,当遍历原始ints
数组的元素时,它还了解到该数组的元素显然是int
。
混合动态特征和静态类型方法
要记住的一个重要方面是,使用静态类型检查工具会限制您在Groovy中允许使用的功能。 不允许使用大多数运行时动态功能,因为在编译时无法对其进行静态类型检查。 因此,不允许在运行时通过类型的元类添加新方法。 但是,当您需要使用某些特定的动态功能(例如Groovy的构建器)时,可以根据需要选择退出静态类型检查。
@TypeChecked
批注可以放在类级别或方法级别。 因此,如果要检查整个类的类型,请在类上添加注释,如果只想检查几个方法的类型,则仅在那些方法上添加注释。 另外,如果要检查除特定方法外的所有类型,则可以使用@TypeChecked(TypeCheckingMode.SKIP)
或@TypeChecked(SKIP)
简短地注释后者@TypeChecked(TypeCheckingMode.SKIP)
如果静态导入关联的枚举)。 让我们用以下脚本说明这种情况,其中greeting()
方法是类型检查的,而generateMarkup()
方法不是:
import groovy.transform.TypeChecked
import groovy.xml.MarkupBuilder
// this method and its code are type checked
@TypeChecked
String greeting(String name) {
generateMarkup(name.toUpperCase())
}
// this method isn't type checked
// and you can use dynamic features like the markup builder
String generateMarkup(String name) {
def sw = new StringWriter()
new MarkupBuilder(sw).html {
body {
div name
}
}
sw.toString()
}
assert greeting("Cédric").contains("<div>CÉDRIC</div>")
类型推断和instanceof检查
当前的Java生产版本不支持通用类型推断。 因此,今天我们发现许多地方的代码通常很冗长,并且被样板结构所困扰。 这掩盖了代码的意图,并且如果没有强大的IDE的支持也很难编写。 使用instanceof
检查就是这种情况:您经常在if
条件中使用instanceof
检查值的类,然后在if
块中,仍然必须使用强制类型转换才能使用手头值的方法。 在普通的Groovy中以及在新的静态类型检查模式中,您可以完全摆脱这些强制类型转换。
import groovy.transform.TypeChecked
import groovy.xml.MarkupBuilder
@TypeChecked
String test(Object val) {
if (val instanceof String) {
// unlike Java:
// return ((String)val).toUpperCase()
val.toUpperCase()
} else if (val instanceof Number) {
// unlike Java:
// return ((Number)val).intValue().multiply(2)
val.intValue() * 2
}
}
assert test('abc') == 'ABC'
assert test(123) == '246'
在上面的示例中,静态类型检查器知道val参数在if
块内为String
类型,在else if块内为Number
类型,而不需要任何强制转换。
最低上限
静态类型检查器在类型推断方面走得更远,因为它可以更精细地了解对象的类型。 考虑以下代码:
import groovy.transform.TypeChecked
// inferred return type:
// a list of numbers which are comparable and serializable
@TypeChecked test() {
// an integer and a BigDecimal
return [1234, 3.14]
}
在此示例中,我们直观地返回一个数字列表: Integer
和BigDecimal
。 但是静态类型检查器会计算我们所谓的“最低上限” ,实际上是一系列可序列化和可比较的数字。 不可能用标准Java类型符号来表示该类型,但是如果我们有某种类似“&”的交集运算符,它可能看起来像List<Number & Serializable & Comparable>.
流式
尽管实际上并不建议这样做,但是有时开发人员会使用相同的无类型变量来存储不同类型的值。 看一下这个方法体:
import groovy.transform.TypeChecked
@TypeChecked test() {
def var = 123 // inferred type is int
var = "123" // assign var with a String
println var.toInteger() // no problem, no need to cast
var = 123
println var.toUpperCase() // error, var is int!
}
var
变量使用int
初始化。 然后,分配一个String
。 “流类型”算法遵循赋值流程,并且知道该变量现在包含一个String
,因此静态类型检查器将对Groovy在String
之上添加的toInteger()
方法感到满意。 接下来,在var变量中放一个数字,但是随后,当调用toUpperCase()
,类型检查器将引发编译错误,因为Integer
上没有toUpperCase()
方法。
当变量与闭包共享时,流类型算法有一些特殊情况,这很有趣。 在定义该变量的方法中的闭包中引用局部变量时,会发生什么情况? 让我们看一下这个例子:
import groovy.transform.TypeChecked
@TypeChecked test() {
def var = "abc"
def cl = {
if ( new Random().nextBoolean()) var = new Date()
}
cl()
var.toUpperCase() // compilation error!
}
为var
局部变量分配了一个String
,但是,如果某个随机值是true,则可以为var
分配一个Date
。 通常,只有在运行时我们才真正知道关闭的if语句中的条件是否成立。 因此,在编译时,编译器没有机会知道var
现在是否包含String
或Date
。 这就是为什么编译器实际上会抱怨toUpperCase()
调用的原因,因为它无法推断变量是否包含String
。 这个例子当然有些虚构,但是还有一些更有趣的情况:
import groovy.transform.TypeChecked
class A { void foo() {} }
class B extends A { void bar() {} }
@TypeChecked test() {
def var = new A()
def cl = { var = new B() }
cl()
// var is at least an instance of A
// so we are allowed to call method foo()
var.foo()
}
在上面的test()
方法中,为var
分配了一个A
实例,然后在闭包中为其分配了一个B
实例,之后再调用它,因此我们至少可以推断出var的类型为A
添加到Groovy编译器的所有这些检查都是在编译时完成的,但是生成的字节码仍然是与通常相同的动态代码-行为完全没有变化。
由于编译器现在在类型方面对程序有了更多的了解,因此打开了一些有趣的可能性:如何静态地编译该类型检查的代码? 明显的优点是,生成的字节码将更类似于javac编译器本身创建的字节码,从而使静态编译的Groovy代码像普通Java一样快。 在下一节中,我们将学习更多有关Groovy的静态编译的信息。
静态编译
正如我们将在下一章中有关JDK 7对齐的内容中所看到的那样,Groovy 2.0支持JVM及其相关API的新“调用动态”指令,从而促进了Java平台上动态语言的开发,并为Groovy的动态带来了一些额外的性能。电话。 但是,不幸的是,我要说的是,在撰写本文时,JDK 7尚未在生产中广泛部署,因此并不是每个人都有机会运行最新版本。 因此,如果寻求性能改进的开发人员无法在JDK 7上运行,他们将不会在Groovy 2.0中看到太大的变化。幸运的是,Groovy开发团队认为,这些开发人员可以通过允许类型检查来获得有趣的性能提升以及其他优势。要静态编译的代码。
@CompileStatic
,让我们深入了解并使用新的@CompileStatic
转换:
import groovy.transform.CompileStatic
@CompileStatic
int squarePlusOne( int num) {
num * num + 1
}
assert squarePlusOne(3) == 10
这次,不用@TypeChecked
,而是使用@CompileStatic
,您的代码将被静态编译,并且此处生成的字节码将看起来像javac的字节码一样,运行速度也一样快。 像@TypeChecked annotation, @CompileStatic
一样, @TypeChecked annotation, @CompileStatic
可以注释类和方法,而@CompileStatic(SKIP)
可以在其类标记有@CompileStatic
时绕过特定方法的静态编译。
类似于javac的字节码生成的另一个优点是,那些带注释的方法的字节码的大小将小于Groovy为动态方法生成的普通字节码,因为它支持Groovy的动态功能,因此动态情况下的字节码包含附加指令。调用Groovy的运行时系统。
最后但并非最不重要的一点是,框架或库代码编写者可以使用静态编译来帮助避免在代码库的多个部分中使用动态元编程时产生不利的交互作用。 Groovy等语言提供的动态功能使开发人员拥有了无与伦比的功能和灵活性,但是如果不加注意,关于元编程功能的作用,系统的不同部分可能存在不同的假设,这可能会带来意想不到的后果。 作为一个稍作设计的示例,请考虑如果您使用两个不同的库会发生什么,这两个库都向一个核心类中添加了一个名称相似但实现方式不同的方法。 预期会有什么行为? 经验丰富的动态语言用户以前可能已经看到过此问题,并且可能听说过“猴子补丁” 。 能够静态编译部分代码库(那些不需要动态功能的部分)可以使您免受猴子补丁的影响,因为静态编译的代码不会通过Groovy的动态运行时系统。 尽管该语言的动态运行时方面不允许在静态编译上下文中使用,但是所有常规AST转换机制的运行效果均与以前一样,因为大多数AST转换在编译时都会发挥其魔力。
就性能而言,Groovy的静态编译代码通常与Javac一样快。 在开发团队使用的一些微基准测试中,在某些情况下性能是相同的,有时会稍慢一些。
从历史上看,由于Java和Groovy的透明和无缝集成,我们曾经建议开发人员优化Java中的一些热点例程以进一步提高性能,但是现在有了这种静态编译选项,情况已不再如此,人们希望全面开发他们的项目可以做到这一点。
Java 7和JDK 7主题
Groovy编程语言的语法实际上是从Java语法本身衍生而来的,但是显然,Groovy提供了许多不错的捷径,以使开发人员更加高效。 由于学习曲线平坦,Java开发人员对语法的这种熟悉一直是该项目及其广泛采用的主要卖点。 当然,我们希望Groovy用户和新手也希望从Java 7的“ Project Coin”附加功能中受益。
除了语法方面,JDK 7还为其API带来了有趣的新颖性,甚至很长时间以来,甚至首次出现了名为“调用动态”的新字节码指令,该指令旨在帮助实现者更轻松地开发其动态语言并从中受益。从更多的性能。
项目币语法增强
从第一天开始(那已经是2003年了!),Groovy在Java之上有了一些语法增强和功能。 例如,人们可以想到闭包,而且还可以在switch / case
语句中放置多个离散值,而Java 7仅允许使用Strings
。 因此,Groovy中已经提供了一些Project Coin语法增强功能,例如switch中的Strings
。 但是,其中的一些增强功能是新的,例如二进制文字,数字文字下划线或multi catch块,并且Groovy 2支持它们。 Project Coin增强功能唯一的遗漏是“尝试资源”构造,为此Groovy已经通过Groovy开发工具包的丰富API提供了多种选择。
二进制文字
在Java 6和更低版本以及Groovy中,数字可以十进制,八进制和十六进制为单位表示,对于Java 7和Groovy 2,可以使用带有“ 0b”前缀的二进制表示法:
int x = 0b10101111
assert x == 175
byte aByte = 0b00100001
assert aByte == 33
int anInt = 0b1010000101000101
assert anInt == 41285
在数字文字下划线
当写长文字数字时,很难找出一些数字是如何组合在一起的,例如,成千上万的单词,单词等的组合。通过允许在数字文字中加下划线,可以更容易地发现这些组:
long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010
多捕获块
捕获异常时,我们经常为两个或多个异常复制catch块,因为我们希望以相同的方式处理它们。 解决方法是要么以其自身的方法排除共同点,要么以更丑陋的方式通过捕获Exception
或更糟糕的是Throwable
采用万能的方法。 使用multi catch块,我们能够定义要由同一catch块捕获和处理的几个异常:
try {
/* ... */
} catch (IOException | NullPointerException e) {
/* one block to handle 2 exceptions */
}
调用动态支持
正如我们在本文前面提到的,JDK 7附带了一个新的字节码指令,称为“调用动态” ,及其相关的API。 他们的目标是通过简化动态方法调用的连线,定义可在其中缓存动态方法调用部分的“调用站点” , “方法句柄” ,来帮助动态语言实现者在Java平台之上设计语言。作为方法指针, “类值”可用于存储沿着类对象的任何类型的元数据以及其他一些东西。 需要注意的是,尽管性能有望实现改善,但“调用动态”尚未在JVM内部进行完全优化,并且仍无法始终提供最佳性能,但是在更新后进行更新会带来优化。
Groovy带来了自己的实现技术,以通过“调用站点缓存”加快方法的选择和调用的速度,使用其元类注册表存储元类(与类的动态运行时等效),以与Java一样快地执行本机原始计算,等等。 。 但是随着“调用动态”技术的出现,我们可以在这些API和JVM字节码指令的基础上重新构建Groovy的实现,以提高性能并简化我们的代码库。
如果您幸运地可以在JDK 7上运行,那么您将能够使用新版的Groovy JAR,该版本已通过“调用动态”支持进行编译。 这些JAR在名称中使用“ -indy”分类器,因此很容易识别。
启用调用动态支持
但是,仅使用“ indy” JAR来编译Groovy代码以使其利用“调用动态”支持是不够的。 为此,在使用“ groovyc”编译器或“ groovy”命令时,必须使用--indy标志。 这也意味着即使使用Indy JAR,仍然可以将JDK 5或6作为目标。
同样,如果您使用groovyc Ant任务来编译项目,则还可以指定indy属性:
...
<taskdef name="groovyc"
classname="org.codehaus.groovy.ant.Groovyc"
classpathref="cp"/>
...
<groovyc srcdir="${srcDir}" destdir="${destDir}" indy= " true ">
<classpath>
...
</classpath>
</groovyc>
...
Groovy Eclipse Maven编译器插件尚未在Groovy 2.0的支持下进行更新,但是很快就是这种情况。 对于GMaven插件用户,尽管可以将插件配置为已经使用Groovy 2.0,但是当前没有标记来启用调用动态支持。 同样,GMaven也将在这方面进行更新。
例如,在将Groovy与Java应用程序集成到GroovyShell
,还可以通过将CompilerConfiguration
实例传递给您可以访问并设置优化选项的GroovyShell
构造函数来启用动态调用支持:
CompilerConfiguration config =new CompilerConfiguration();
config.getOptimizationOptions().put( " indy " , true);
config.getOptimizationOptions().put( " int " , false);
GroovyShell shell = new GroovyShell(config);
由于应该将invokedynamic完全替代动态方法分派,因此也有必要禁用原始优化,该优化会生成额外的字节码,从而在此处优化边缘情况。 即使在某些情况下,它的速度比激活原始优化的速度慢,但将来的JVM版本仍将具有改进的JIT,它将能够内联大多数调用并删除不必要的装箱。
有希望的性能改进
在我们的测试中,我们注意到某些方面的性能提升,而其他程序的运行速度可能比不使用invoke动态支持时要慢。 Groovy团队在Groovy 2.1的管道中进一步改进了性能,但是我们注意到JVM尚未进行微调,并且要完全优化还有很长的路要走。 但是幸运的是,即将到来的JDK 7更新(特别是更新8)应该已经包含了此类改进,因此情况只会有所改善。 此外,由于将调用动态用于JDK 8 Lambda的实现,因此我们可以确定还会有更多改进。
更具模块化的Groovy
我们将通过谈论模块化来完成Groovy 2.0的新功能。 与Java一样,Groovy不仅是一种语言,而且还是一组用于各种目的的API:模板,Swing UI构建,Ant脚本,JMX集成,SQL访问,servlet服务等等。 Groovy交付品将所有这些功能和API捆绑在一个大型JAR中。 但是,并非每个人都在任何时候都需要自己的应用程序中的所有内容:如果您正在编写某些Web应用程序,则可能对模板引擎和servlet感兴趣,但是在处理丰富的桌面客户端程序时可能只需要Swing构建器。
Groovy模块
因此,此发行版的模块化方面的首要目标是实际上将原始Groovy JAR拆分为较小的模块,较小的JAR。 现在,核心Groovy JAR的大小是原来的两倍,并且我们提供以下功能模块:
- Ant :用于脚本化Ant任务以自动化管理任务
- BSF :用于将Java中的Groovy与旧的Apache Bean脚本框架集成
- 控制台 :包含Groovy Swing控制台的模块
- GroovyDoc :用于记录您的Groovy和Java类
- Groovysh :与Groovysh命令行外壳相对应的模块
- JMX :用于公开和使用JMX bean
- JSON :用于产生和使用JSON负载
- JSR-223 :用于将Java中的Groovy与JDK 6+ javax.scripting API集成
- Servlet :用于编写和服务Groovy脚本Servlet和模板
- SQL :用于查询关系数据库
- Swing :用于构建Swing UI
- 模板 :用于使用模板引擎
- 测试 :获得一些测试支持,例如GroovyTestCase,模拟等等
- TestNG :用于在Groovy中编写TestNG测试
- XML :用于生成和使用XML文档
使用Groovy 2,您现在可以只选择您感兴趣的模块,而不必将所有内容都放在类路径中。 但是,如果您不想为了节省几MB的空间而使依赖项复杂化,我们仍然提供包含所有内容的“全部” JAR。 对于在JDK 7上运行的JAR,我们还为这些JAR提供了“调用动态”支持。
扩展模块
使Groovy更具模块化的工作还产生了一个有趣的新功能:扩展模块。 通过将Groovy拆分为较小的模块,已创建了一种模块来贡献扩展方法的机制。 这样,扩展模块可以为其他类(包括来自JDK或第三方库的类)提供实例和静态方法。 Groovy使用此机制来装饰JDK中的类,向String, File
,streams等类添加新的有用方法-例如,URL上的getText()
方法允许您通过以下方法检索远程URL的内容HTTP get。 还要注意,静态类型检查器和编译器也可以理解模块中的那些扩展方法。 现在让我们看一下如何向现有类型添加新方法。
贡献实例方法
要将新方法添加到现有类型,则必须创建一个包含这些方法的帮助程序类。 在该帮助器类中,所有扩展方法实际上都是public
(Groovy的默认方法,但如果用Java实现,则是必需的)和static
(尽管它们可以在该类的实例上使用)。 他们将始终采用第一个参数,该参数实际上是将在其上调用此方法的实例。 然后,以下参数将是调用该方法时传递的参数。 这与Groovy类别的约定相同。
假设我们要在String,
上添加greets()
方法String,
该方法将问候传入参数的人的名字,以便您可以按以下方式使用该方法:
assert "Guillaume".greets("Paul") == "Hi Paul, I'm Guillaume"
为此,您将创建一个具有扩展方法的helper类,如下所示:
package com.acme
class MyExtension {
static String greets(String self, String name) {
"Hi ${name}, I'm ${self}"
}
}
贡献静态方法
对于静态扩展方法,这是相同的机制和约定。 让我们为Random添加一个新的静态方法,以获取两个值之间的随机整数,您可以按照此类进行操作:
package com.acme
class MyStaticExtension {
static String between(Random selfType, int start, int end) {
new Random().nextInt(end - start + 1) + start
}
}
这样,您便可以如下使用该扩展方法:
Random.between(3, 4)
扩展模块描述符
在对包含扩展方法的辅助类(使用Groovy甚至Java)进行编码后,您需要为模块创建一个描述符。 您必须在模块档案的META-INF/services
目录中创建一个名为org.codehaus.groovy.runtime.ExtensionModule
的文件。 可以定义四个基本字段,以向Groovy运行时告知模块的名称和版本,并以逗号分隔的类名列表指向扩展方法的帮助程序类。 这是我们最终的模块描述符:
moduleName = MyExtension
moduleVersion = 1.0
extensionClasses = com.acme.MyExtension
staticExtensionClasses = com.acme.MyStaticExtension
通过在类路径上使用此扩展模块描述符,您现在可以在代码中使用那些扩展方法,而无需导入或其他任何操作,因为这些扩展方法是自动注册的。
抓住扩展
在脚本中使用@Grab批注,您可以从Maven存储库(如Maven Central)中获取依赖项。 通过添加@GrabResolver批注,您还可以为依赖项指定自己的位置。 如果通过这种机制“抓住”扩展模块的依赖性,扩展方法也将自动安装。 理想情况下,为了保持一致性,您的模块名称和版本应该与工件ID和工件的版本一致。
摘要
Groovy在Java开发人员中非常受欢迎,并为他们提供了成熟的平台和生态系统来满足他们的应用程序需求。 但是,在不停歇的情况下,Groovy开发团队继续改进该语言及其API,以帮助其用户在Java平台上提高生产力。
Groovy 2.0响应了三个关键主题:
- 更高的性能 :在JDK 7 Invoke Dynamic的支持下 ,可以为那些幸运地将JDK 7投入生产的用户加快Groovy的运行速度,而且还为每个人提供针对JDK 5以及更高版本的静态编译 ,尤其是那些准备放弃某些动态特性的人。保护自己免受“猴子修补”的影响,并获得与Java相同的速度 。
- 更多Java友好性 :借助Java 7 Project Coin增强功能的支持,使Groovy和Java保持与以往一样紧密的语法表亲,并且静态类型检查器具有与javac编译器为开发人员提供的相同级别的反馈和类型安全性使用Groovy作为Java脚本语言
- 更高的模块化 :通过更高级别的模块化,Groovy为较小的交付物打开了大门,例如,可以集成到Android上的移动应用程序中,并允许Groovy API随着新版本和新扩展模块的增长和发展,以及允许用户为现有类型贡献扩展方法。
groovy 2.5.4