`
fulerbakesi
  • 浏览: 564205 次
文章分类
社区版块
存档分类
最新评论

Groovy – Java的脚本语言

 
阅读更多

介绍

Groovy是用Java实现的开源脚本语言并且和它联系紧密.它需要JDK 1.4. GroovyJava添加了许多RubyPython脚本语言的特性. Groovy的特性包括动态类型(dynamic typing, 闭包(closures,简单对象导航( easy object navigation)和更加简洁的ListsMaps语法.所有这些特性和其他一些特性将会在本文中详细介绍.

这里引用Groovy网页上的话. "Groovy是设计用来以精简快速有趣的方式来在Java平台上处理事务,并且把类似Python Ruby等的强大功能带到Java的世界里."

Groovy脚本可以使用任何Java.它们可以被编译成Java字节码 (.class文件)并能被任何正常的Java类引用.Groovy编译器, groovyc,可以编译Groovy脚本文件和Java源文件,然而有些语法(例如内类)并不被支持.

理论上, 可以使用Groovy编写完整的应用程序,其具有和同等Java应用程序差不多的性能.这是Groovy和其他脚本语言不一样的如Ruby, Python, Perl以及BeanShell. 使Groovy现在运行得比Java还慢的原因之一是生成的字节码使用了映射(reflection)来调用构造函数以及私有/保护的方法.这个问题将会在以后的版本中解决.

Groovy是由James StrachanBob McWhirter创造的. James还参与了许多其他开源项目的开发,其中包括Jelly, dom4j, Jaxen, BetwixtMaven. BobJaxenDrools (一个开源的面向对象的JAVA规则引擎) 的创始人.

本文并没有涉及Groovy所有的特性,而只是涉及了其中的大部分.它假设你对Java的语法有足够的了解并能把JavaGroovy的语法进行比较.

如果我们能在好的编程语言使用什么样的语法的问题上达成一致的话那么我们就不需要那么多语言了.这样大量的程序设计语言会被排除在外,显然我们并不同意.Based on the number of programming languages out there, we obviously don't agree.)在读完本文之后,你可能认为Java的语法已经可以了并且认为Groovy的语法不太合你的口味.如果你的结论是这样,我鼓励你研究Pat Niemeyer BeanShell位于http://www.beanshell.org/.它更加接近于标准的Java语法.另一方面,如果你喜欢Groovy的简短的语法那么就一起groovy!

下载并安装Groovy

使用以下步骤可以下载Groovy.

1. 访问 http://groovy.codehaus.org/.

2. 点击下载顶部导航栏中的"Download".

3. 点击 "this site" 链接.

4. 选择一个版本下载.

CVS中可以下载最新的版本. 操作步骤的说明在这里可以找到.

要安装Groovy, 使用以下步骤.

1. 解压下载的文件.

2. 把环境变量GROOVY_HOME 设置到解压的目录.

3. 向环境变量PATH添加$GROOVY_HOME/bin (UNIX)%GROOVY_HOME%/bin (Windows).

运行Groovy

运行Groovy脚本有四种方式.在这些方式中,脚本会被解析, 转换成Java源代码以及编译成Java字节码(bytecode.

互动的Shell

命令groovysh启动了一个互动的shell,可以在那里输入Groovy语句.输入一些语句,在每个语句结尾按回车(enter)键. 语句不会被求值(evaluated)或执行,直到输入execute命令为止.

互动的Swing Console

groovyConsole命令会启动一个Swing窗口.在窗口的下半部分输入Groovy语句.Actions菜单中选择Run来运行他们.输出的内容在窗口的上半部分显示. 使用File 菜单中可以打开和保存脚本文件.


运行脚本文件

一个Groovy脚本文件 (扩展名为.groovy的文件)可以使用命令groovy script-name.groovy来运行.

运行编译好的脚本

使用命令 groovyc script-name.groovy一个Groovy的脚本文件可以被编译为Java .class文件. 如果在脚本文件中使用了松散的语句(loose statements, .class文件中会包含一个main方法,这样它就可以象Java应用程序一样使用命令java script-name运行. Main方法的内容会在后面提到. classpath 必须包含Groovy lib目录中的groovy*.jarasm*.jar文件.

有一个定制的Ant任务完成这个任务!这个类是org.codehaus.groovy.ant.Groovyc.

一些语法细节

以下是JavaGroovy语法关键的不同之处.其他的我们会在后面谈到.

· 它的目标是支持所有合法的Java语法, 但是这个目标暂时还未达到.

· 每行语句结尾的分号是可有可无的.

· 方法的参数旁边的圆括号也是可有可无的除非该方法没有参数或者是不加圆括号会造成歧义.但是,构造函数中的圆括号则是必需的.有些人更倾向于经常使用圆括号. 本文则倾向于在允许的情况下省略它.

· "return"语句在某些时候也是可有可无的.当一个方法要返回值的时候,如果执行到大括号(方法结尾的大括号)前的最后一条语句,那么就会把它的值作为返回值.以后Groovy可能会改成返回最后执行的那一条语句计算出来的值.

· Groovy 属性和方法默认的情况下是公开的(public,而不是象JAVA中是受保护的( protected. 稍后我们再讨论Groovy Beans.

· java.lang, groovy.langgroovy.util会被自动导入.

动态类型(Dynamic Typing

类型对于变量,属性,方法/闭包的参数(method/closure parameters)以及方法的返回类型都是可有可无的.他们都是在赋值给他们的时候才决定类型. 不同的类型会在后面用到.任何类型都可以被使用,即使是基本类型 (通过自动包装(autoboxing). 当需要时,很多类型之间的转换都会自动发生,比如在这些类型之间的转换: 字符串(String,基本类型(int) 和类型的包装类(type wrapper classes (Integer)之间.我们也可以把不同的基本类型添加到同一数组(collections)中.

Added Methods

Groovy向标准Java类添加了许多方法例如java.lang.Object java.lang.String.可以在http://groovy.codehaus.org/groovy-jdk.html找到那些添加的方法.其他的我们以后再谈.

dump

该操作返回如下形式的字符串 <class-name@hashcode property-name=property-value ...> 例如, <Car@ef5502 make=Toyota model=Camry>.

Printprintln

这两个静态方法打印对象的toString 方法的值.例如, print car println car.

invokeMethod

这个操作使用映射(reflection)实现动态方法调用.语法格式是object.invokeMethod(method-name, argument-array).下面的例子会打印数值4.

s = 'abcabc' // a java.lang.String

method = 'indexOf'

args = ['b', 2]

println s.invokeMethod(method, args)

Groovy 字符串

字符串可以使用双引号也可以使用单引号. 当使用双引号的时候,可以在其中包含内嵌值(embedded values.包含内嵌值的语法格式是${expression} Ruby语言中差不多,只是这里使用了$Ruby中使用的是#.使用双引号的字符串其中包含了至少一个内嵌值,那么它就是groovy.lang.GString 类的对象. 其他的字符串都是java.lang.String类的对象. 在需要的时候Gstrings会被强制自动转换为java.lang.String.

针对Groovy类如groovy.lang.GStringJavadoc可以在http://groovy.codehaus.org/apidocs/找到.

内嵌值对于实现toString方法很有帮助. 例如,

String toString() { "${name} is ${age} years old." }

多行字符串可以用三种方式创建.下面的例子是等效的.最后一个例子使用了被称为 "here-doc"的方式. 在三个小于号之后,就是指定的分隔符字符串.字符串的值包括分隔符字符串出现的两次之间的所有字符. "EOS" (代表"End Of String"字符串的结尾的意思) 是个普通的分隔符,其他的分割符同样也可以使用.

s = " This string

spans three /"lines/"

and contains two newlines."

s = """ This string

spans three "lines"

and contains two newlines."""

s = <<<EOS

This string

spans three "lines"

and contains two newlines.

EOS

注意:在前面的代码片段中最后一行的字符没有被保存在字符串中.

以下的方法被添加到java.lang.String类中.

contains

该操作判断一个字符串中是否含有给定的子串. 'Groovy'.contains('oo') 则返回true.

count

该操作统计某子串在给定字符串中出现的次数. 'Groovy Tool'.count('oo')返回结果 2.

tokenize

该操作使用给定的分隔符把字符串分割成令牌(token)并返回令牌(token)的集合.指定分隔符参数是可选的.默认的间隔符是空格. 'apple^banana^grape'.tokenize('^')返回结果['apple', 'banana', 'grape'].

minus

该操作会除去字符串中给定子串第一次出现的部分. 'Groovy Tool' - 'oo' 返回'Grvy Tool'.

multiply

这个操作会把给定的字符串重复给定的次数. 'Groovy' * 3返回'GroovyGroovyGroovy'.

正则表达式 (regex)

首先,我们来回顾一下J2SE 1.4对正则表达式的支持.那么我们来看看Groovy是怎么实现的.

J2SE 1.4, java.util.regex包中的类支持正则表达式. 模式(Pattern 对象代表一个编译过的regex.它们是使用Pattern.compile("pattern")创建的. 该类的Javadoc描述了正则表达式的语法. Matcher 对象保存一个模式与一个字符串匹配的结果.它们是使用pattern.matcher("text")创建的.为了判断文本是否与模式想匹配, 我们使用matcher.matches(). 模式中的/必须有与之相对应的/.

Groovy3种方法可以支持正则表达式.
~"pattern" 创建一个模式对象并等同于 Pattern.compile("pattern").
"text" =~ "pattern" 创建一个 Matcher对象并等同于Pattern.compile("pattern").matcher("text").
"text" ==~ "pattern"返回一个布尔值,等同于Pattern.compile("pattern").matcher("text").matches().更多的方法可以参见模式和Matcher javadoc.

例如,

pattern = "//d{5}" // matches zip codes (5 digits)

text = "63304" // a zip code

println text ==~ pattern // prints "true"

m = text =~ pattern

println m.matches() // prints "true"

// The next line requires a literal string for the pattern.

// A variable can't used.

p = ~"//d{5}"

m = p.matcher(text)

println m.matches() // prints "true"

Groovy脚本

Groovy的脚本文件通常是以".groovy"为后缀名的. 它们可以包含 (以任何顺序)松散语句(loose statements, 与类无联系的方法定义, 以及类定义.

例如,

// These are loose statements.

println 'loose statement'

myMethod 'Mark', 19

println new MyClass(a1:'Running', a2:26.2)

// This is a method definition that

// is not associated with a class.

def myMethod(p1, p2) {

println "myMethod: p1=${p1}, p2=${p2}"

}

// This is a definition of a class that

// has two properties and one method.

class MyClass {

a1; a2

String toString() { "MyClass: a1=${a1}, a2=${a2}" }

}

方法和类的定义不需要放在它们被使用之前.在与类相关联的基本文件中松散方法会被编译为相应类中的静态方法.例如, Bar.groovy脚本中一个叫foo的松散方法会在类Bar中被编译成叫foo的静态方法.松散语句回被收集到run方法,由编译生成的main方法调用该方法

groovyc被用来便宜一个脚本的时候,生成的类会有一个包含了所有的松散语句的run方法以及调用run方法的main方法.

目前脚本还不能引用其他脚本中的代码除非他们是编译好的并被引入了的. 这会在不久之后改进.

运算符重载

Groovy支持一部分运算符的运算符重载.每个运算符对应于一个特定的方法. 只要在你的类中实现这些方法就使用相应的运算符调用这些方法对这些类的对象进行操作.方法可以被重载来对不同类型的参数进行操作.

比较运算符

a == b对应a.equals(b)
a != b对应!a.equals(b)
a === b对应Java中的a == b
a <=> b对应a.compareTo(b)
a > b对应a.compareTo(b) > 0
a >= b
对应a.compareTo(b) >= 0
a < b
对应a.compareTo(b) < 0
a <= b
对应a.compareTo(b) <= 0

比较运算符可以处理null值并且不会生成NullPointerException. Null被认为比任何值都小.

注意到在Groovy== 运算符被用来判断两个对象是否具有相同的值而=== 运算符被用来判断它们是否是内存中的同一对象.

compareTo方法返回一个int 值,如果a < b则返回小于0的值, 如果a > b则返回大于0的值, 如果a 等于 b则返回0.

其他运算符

a + b对应a.plus(b)
a - b对应a.minus(b)
a * b对应a.multiply(b)
a / b对应a.divide(b)
a++ and ++a对应a.increment(b)
a-- and --a对应a.decrement(b)
a[b] 对应a.get(b)
a[b] = c对应a.put(b, c)

Groovy闭包

一个闭包就是可以使用参数的代码片段. 每个闭包会被编译成继承groovy.lang.Closure类的类.这个类有一个叫call方法,通过该方法我们可以传递参数并调用这个闭包.它们可以访问并修改在闭包创建的范围内的变量(They can access and modify variables that are in scope when the closure is created.)在闭包内创建的变量在闭包被调用的范围内同样可以被引用. 闭包可以保存在变量中并被作为参数传递到方法中.这在某些list, mapstring方法非常有用,我们会在以后提到.

定义闭包的语法格式是

{ comma-separated-parameter-list | statements }

例如,

closure = { bill, tipPercentage | bill * tipPercentage / 100 }

tip = closure.call(25.19, 15)

tip = closure(25.19, 15) // 与上一行等效

传递了错误的参数数量会产生IncorrectClosureArgumentException.

关键字it用于只有一个参数的闭包.参数列表可以被省略而在语句中使用it代表参数.例如,下面的闭包是等效的.

{ x | println x }

{ println it }

下面是一个方法的例子,它使用了一个List和一个闭包作为参数.它被写成一个"松散方法",但是它同样可以被写成某个类的一个方法.方法遍历这个List, List中的每个项目调用闭包.它使用闭包返回true的项目生成一个新的List然后返回新的List. 注意Groovy提供的findfindAll方法可以替代它.

def List myFind(List list, Closure closure) {

List newList = []

for (team in list) {

if (closure.call team) newList.add team

}

newList

}

下面是使用这个方法的例子.

class Team { name; wins; losses }

teams = []

teams.add new Team(name:'Rams', wins:12 , losses:4)

teams.add new Team(name:'Raiders', wins:4 , losses:12)

teams.add new Team(name:'Packers', wins:10 , losses:6)

teams.add new Team(name:'49ers', wins:7 , losses:9)

winningTeams = myFind(teams) { it.wins > it.losses }

winningTeams.each { println it.name }

没必要编写一个象myFind的方法因为List类中 已经有一个findAll方法了.象下面这样使用它,

winningTeams = teams.findAll { it.wins > it.losses }

Groovy Beans

这里是一个 Groovy Bean例子.

class Car {

String make

String model

}

这个类声明了两个属性,而不包含任何方法.然而,很多事情是在后台完成的. ,属性和方法默认是公共的(public.公共的和保护的(protected)属性会成为私有域但是它们的公共的/保护的get set 会被自动生成.Public and protected properties result in private fields for which public/protected get and set methods are automatically generated)这些都可以被重载来提供定制的行为.对于明确被声明为私有的(private)属性来说, getset 方法没有被生成.

上面的Groovy代码等同于以下的Java代码.

public class Car {

private String make;

private String model;

public String getMake() {

return make;

}

public String getModel() {

return model;

}

public void setMake(String make) {

this.make = make;

}

public void setModel(String model) {

this.model = model;

}

}

Groovy Beans生成的类继承了java.lang.Object并实现了groovy.lang.GroovyObject.它添加的方法有getProperty, setProperty, getMetaClass, setMetaClass以及invokeMethod. groovy.lang.MetaClass允许在运行时添加方法.

Groovy Beans可以使用有名参数创建.例如,下面的代码调用了Car类的无参数构造函数然后调用了每个独立属性的set方法.

myCar = new Car(make:'Toyota', model:'Camry')

Groovy Lists

Groovy listsjava.util.ArrayList类的实例.它们可以使用方括号内部的逗号分隔的值表来创建. 例如,

cars = [new Car(make:'Honda', model:'Odyssey'),

new Car(make:'Toyota', model:'Camry')]

println cars[1] //指的是Camry

for (car in cars) { println car } //调用CartoString方法

class Car {

make; model

String toString() { "Car: make=${make}, model=${model}" }

}

为了确定从list的末端开始计算的list的元素的位置,我们使用负数索引(negative indexes.

空的lists可以用[]创建.例如,

cars = []

有两种方式添加元素.

cars.add car

cars << car

List可以使用数组调用array.toList()方法创建.数组同样可以使用list调用list.toArray()方法创建.

Groovy还向java.util.List添加了一些方法.

count

该操作计算list中有多少个元素与给定的对象相等.
[1, 2, 3, 1].count(1)返回2.

immutable

该操作使用java.util.Collections类的静态方法unmodifiableList创建一个集合的不能修改的拷贝.例如,

list = [1, 2, 3].immutable()

list.add 4 //抛出java.lang.UnsupportedOperationException异常

intersect

该操作创建一个含有两个给定list的公共元素的list.
[1, 2, 3, 4].intersect([2, 4, 6])返回[2, 4].

join

该操作用给定的字符串连接list中元素的toString的值.例如,它在list的所有字符串元素中间插入了一个’^’分隔符.
['one', 'two', 'three'].join('^')返回"one^two^three".

sort

该操作对list元素进行排序并创建一个新的list.排序可以接受用java.util.Comparator或闭包作为参数.

fruits = ['kiwi', 'strawberry', 'grape', 'banana']

// 下一行返回 [banana, grape, kiwi, strawberry].

sortedFruits = fruits.sort()

//下一行返回[kiwi, grape, banana, strawberry].

sortedFruits =

fruits.sort {l, r | return l.length() <=> r.length()}

上面的最后一个sort方法调用是把闭包作为方法参数的例子.Groovy有很多方法可以做这件事.

Groovy Beans可以很容易的对多属性进行排序.假设有一个Player bean带有属性name, agescore.可以对这些beanlist players基于age然后基于score进行排序.

players.sort { [it.age, it.score] }

min / max

这两个操作分别找出最小或最大的list元素或字符串字符.它们可以接受用java.util.Comparator或闭包作为参数. 例如, 它们找出一个list中最小和最大的数字.
[5, 9, 1, 6].min()返回1.
[5, 9, 1, 6].max()返回9.

reverse

该操作颠倒(反序)list中元素的位置或者字符串中字符的位置.
[1, 2, 3].reverse()返回[3, 2, 1].

Groovy重载了plusminus运算符用于对java.util.List对象进行操作.

plus

该操作创建两个lists的一个合集,并且删去重复的元素.
[1, 2, 3] + [2, 3, 4]返回[1, 2, 3, 2, 3, 4].

minus

该操作删除第一个list中所有在第一个和第二个list都出现的元素.
[1, 2, 3, 4] - [2, 4, 6] 返回[1, 3].list元素不是primitives,则使用 equals方法比较它们.

Groovy Maps

Groovy mapsjava.util.HashMap类的实例. 他们可以使用方括号内部的逗号分隔的关键字/值对的list来创建. 关键字与值之间用冒号隔开. 例如,

players = ['baseball':'Albert Pujols',

'golf':'Tiger Woods']

println players['golf'] // 打印Tiger Woods

println players.golf // 打印Tiger Woods

for (player in players) {

println "${player.value} plays ${player.key}"

}

// 和前面的循环是一样的效果.

players.each {player |

println "${player.value} plays ${player.key}"

}

空的map可以使用 [:]创建.例如,

players = [:]

Groovy Switch

Groovy switch语句中可以使用任何对象包括类, List, RangePattern. Case语句使用isCase方法进行值的比较.这里提供了很多isCase方法的重载版本. 除非对于特定类型进行重载, 否则isCase使用equals方法.当一个case后面跟的是一个类名时, isCase使用instanceof. isCase方法在你的类中被重载.

下面是 switch语句对不同类型的值操作的例子.

switch (x) {

case 'Mark':

println "got my name"

break

case 3..7:

println 'got a number in the range 3 to 7 inclusive'

break

case ['Moe', 'Larry', 'Curly']:

println 'got a Stooge name'

break

case java.util.Date:

println 'got a Date object'

break

case ~"//d{5}":

println 'got a zip code'

break

default:

println "got unexpected value ${x}"

}

Groovy Ranges

使用"..""..."运算符创建Range.下面是一些例子.

3..7 创建一个range37
3...7创建一个range36
"A".."D"创建一个range"A""D"
"A"..."D"创建一个range"A""C"

Range是继承自java.util.AbstractList类并实现了groovy.lang.Range接口的类的对象.一个Range是一个不可修改的List. Range接口添加了getFromgetTo方法来获得下界和上界的值. Range接口提供了两种实现. 当范围限制是整数值时使用groovy.lang.IntRange.它添加了一个contains 方法用于判断一个值是否在range. 当范围限制是其他类型时使用groovy.lang.ObjectRange.它同样有contains方法,但是它仅仅只在作为范围限制的对象实现了java.lang.Comparable的时候有用.

Ranges 在循环中非常有用.参见下一部分的例子.

Groovy Looping

下面是在某一范围循环的6种方法.

for

for (i in 1..1000) { println i }

while

i = 1

while (i <= 1000) { println i; i++ }

each

(1..1000).each { println it }

times

1000.times { println it }

//循环从0999的值

upto

1.upto(1000) { println it }

step

1.step(1001, 1) { println it }

//循环从11000的值;

// stopping one before the parameter value

List/Map/String方法接受闭包作为参数

一些List, MapString方法接受闭包作为参数.

each

该操作用于遍历集合中的元素或者字符串中的字符.它为使用java.util.Iterator提供了另一种选择,可以得到更简单的代码.例如, 打印一个List中的每一个数
[5, 9, 1, 6].each {x | println x}

[5, 9, 1, 6].each {println it}

collect

该操作用于把一个集合或字符串转换成一个新的集合或字符串.例如,List中的每个数都翻倍然后创建一个新的List
doubles = [5, 9, 1, 6].collect {x | x * 2}
doubles赋值为[10, 18, 2, 12].

find

该操作用于找到第一个符合条件的集合元素或者字符串字符. 例如,找到list第一个大于5的数
[5, 9, 1, 6].find {x | x > 5}返回9.

findAll

该操作用于找到所有符合条件的集合元素或者字符串字符. 例如,找到list中所有大于5的数
[5, 9, 1, 6].findAll {x | x > 5} 返回 [9, 6].

every

该操作用于判断是否集合的每一个元素或者字符串的每一个字符都符合给定的条件. 例如, 判断List中所有的数是否都小于7
[5, 9, 1, 6].every {x | x < 7} 返回 false.

any

该操作用于判断是否存在集合中的元素或者字符串的字符符合给定的条件.例如,判断List中是否存在小于7的数
[5, 9, 1, 6].any {x | x < 7} 返回 true.

inject

该操作用于把值传给第一次遍历然后再把每次遍历的值作为参数传给下一次. 例如, 5的阶乘(用一种不常见的方式)

factorial = [2, 3, 4, 5].inject(1) {

prevResult, x | prevResult * x

}

该闭包被执行了四次.
1)
1 * 2
2)
2 * 3
3)
6 * 4
4)
24 * 5
它返回120.

文件I/O

读取文件中的行(两种选择)

下面代码范例中的省略号 (...) 表示省略了的代码.

file = new File('myFile.txt')

file.eachLine { println it }

lineList = file.readLines()

读取文件中的字节(两种选择)

file = new File('myFile.txt')

file.eachByte { println it }

byteList = file.readBytes()

读取目录中的文件

dir = new File('directory-path')

dir.eachFile { file | . . . }

读取文件并关闭资源

这些方法通过一个Reader或者InputStream读取文件并且保证最后会关闭资源不管是否出现了例外.

file.withReader { reader | . . . }

reader.withReader { reader | . . . }

inputStream.withStream { is | . . . }

写文件并关闭资源

这些方法通过一个WriterOutputStream写文件并且保证最后会关闭资源不管是否出现了例外.

file.withWriter { writer | . . . }

file.withPrintWriter { pw | . . . }

file.withOutputStream { os | . . . }

writer.withWriter { writer | . . . }

outputStream.withStream { os | . . . }

’<<’运算符

添加到字符串

s = 'foo'

s = s << 'bar'

添加到一个StringBuffer

sb = new StringBuffer('foo')

sb << 'bar'

添加到list

colors = ['red', 'green']

colors << 'blue'

写到数据流的末端

w = new File('myFile.txt').newWriter()

w << 'foo' << 'bar'

w.close()

对象导航(Object Navigation

对象之间的关系(graphs)可以通过类似Xpath的语法使用点 (".")运算符来表现.为了避免产生NullPointerException例外, 使用运算符"->" 代替".".例如,

class Team {

String name

Person coach

players = []

}

class Person {

String name

}

p = new Person(name:'Mike Martz')

t = new Team(name:'Rams', coach:p)

//下一行打印和team.getCoach().getName()相同的内容.

println "coach = ${t.coach.name}"

t = new Team(name:'Blues')

// 下一行返回空,

//不会抛出NullPointerException例外.

println "coach = ${t->coach->name}"

// 下一行抛出NullPointerException例外.

println "coach = ${t.coach.name}"

Groovy Reflection

假设你想通过一个对象得到一个类对象.Java中使用someObject.getClass()完成这件事.Groovy,使用someObject.class完成.

假设你想通过一个类名得到一个类对象.JavaGroovy中使用SomeClass.classClass.forName("pkg.SomeClass")完成这件事.

打印Groovy Gstring所有方法的列表,

GString.class.methods.each { it.name }

打印Java接口java.util.List中所有方法的列表,

java.util.List.class.methods.each { it.name }

捕捉没有实现的方法

可以编写类来捕捉没有实现的方法.例如,

o = new CatchCall()

// The next line prints "unknown method Mark called with [19]".

println o.foo("Mark", 19)

class CatchCall {

invokeMethod(String name, Object args) {

try {

return metaClass.invokeMethod(this, name, args)

} catch (MissingMethodException e) {

//可以在这里插入

//处理特定方法和参数的特殊逻辑.

return "unknown method ${name} called with ${args}"

}

}

}

Groovy Markup

GroovyMarkup 使用invokeMethod方法来捕捉刚刚提到的那些不存在的方法并把它们转换为结点” ("nodes"). 方法的参数被看作是结点的属性.方法后的闭包被看作是结点的内容(Parameters to the methods are treated as attributes of the nodes.Closures after the methods are treated as the content of the nodes. )它有和多作用包括

· 构建泛型,数据结构树 (NodeBuilder)

· 构建DOM(DOMBuilder)

· firing SAX事件(SAXBuilder)

· 创建HTMLXML的字符串 (MarkupBuilder)

· 执行Ant任务 (AntBuilder)

· 创建Swing用户接口(SwingBuilder)

另外, 定制的builder可以通过继承groovy.util.BuilderSupport类来创建.

生成HTML

下面是使用 MarkupBuilder生成HTML的例子.

import groovy.xml.MarkupBuilder

mb = new MarkupBuilder()

mb.html() {

head() {

title("This is my title.")

}

body() {

p("This is my paragraph.")

}

}

println mb

这段代码生成了下面的HTML文件.

<html>

<head>

<title>This is my title.</title>

</head>

<body>

<p>This is my paragraph.</p>

</body>

</html>

生成XML

下面是使用MarkupBuilder生成XML的例子.

import groovy.xml.MarkupBuilder;

mb = new MarkupBuilder()

mb.autos() {

auto(year:2001, color:'blue') {

make('Toyota')

model('Camry')

}

}

println mb

这段代码生成了下面的XML文件.

<autos>

<auto year='2001' color='blue'>

<make>Toyota</make>

<model>Camry</model>

</auto>

</autos>

Groovy SQL

Groovy使JDBC更简单. groovy.sql.Sql提供了一个简单的方式来运行一个查询(query)以及遍历ResultSet中的的列.在下面的例子中, MusicCollection是一个数据库的名字(在本例中,已经被注册为一个ODBC 数据源), Artists是给数据库中一个表的名字,Name则是该表中的列名.

import groovy.sql.Sql

dbURL = 'jdbc:odbc:MusicCollection'

jdbcDriver = 'sun.jdbc.odbc.JdbcOdbcDriver'

sql = Sql.newInstance(dbURL, jdbcDriver)

sql.eachRow('select * from Artists') {

println it.Name

}

Groovlets

Groovlets可以拿来取代ServletsJSP.它提供了以下的隐性变量(implicit variables.

· out等同于HttpServletResponse.getWriter()方法

· request等同于 HttpServletRequest

· session -等同于HttpSession

下面是一个Groovlet例子.它能保存为一个名为SimpleGroovlet.groovy的文件.它使用"here-doc"来生成HTML文件.

out.println <<<EOS

<html>

<head>

<title>My Simple Groovlet</title>

</head>

<body>

<h1>My Simple Groovlet</h1>

<p>Today is ${new java.util.Date()}.</p>

</body>

</html>

EOS

GroovyServlet编译Groovlet并会为它们提供缓存加速(cache)直到它们的内容发生改变.Groovlet改变了之后,GroovyServlet会自动重新编译Groovlet. GroovyServlet必须在web.xml中注册.

下面是web.xml文件的一个例子仅仅示范了注册GroovyServlet的部分.

<?xml version="1.0"?>

<!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

<servlet>

<servlet-name>Groovy</servlet-name>

<servlet-class>groovy.servlet.GroovyServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>Groovy</servlet-name>

<url-pattern>*.groovy</url-pattern>

</servlet-mapping>

</web-app>

Groovlets可以使用Ant来部署.基本步骤是

1. 使用下面的内容创建一个WAR.

o 上面的Groovlet源文件(*.groovy)

o WEB-INF 文件夹中的web.xml

o WEB-INF/lib文件夹中的 groovy*.jar asm*.jar文件

2. 在一个servlet 引擎如Tomcat中部署这个WAR.

下面是做这件事的Ant构造文件.

build.properties

build.dir=build

src.dir=src

# Directory that contains Groovlets

groovy.dir=${src.dir}/groovy

# Directory that contains web.xml

web.dir=${src.dir}/web

# Path to WAR that will be produced

war.file=${build.dir}/${ant.project.name}.war

# Where the WAR should be deployed

webapps.dir=${env.TOMCAT_HOME}/webapps

# JARs that must be in the WAR

asm.jar=${env.GROOVY_HOME}/lib/asm-1.4.1.jar

groovy.jar=${env.GROOVY_HOME}/lib/groovy-1.0-beta-4-snapshot.jar

build.xml

<project name="GroovletExample" default="deploy">

<property environment="env"/>

<property file="build.properties"/>

<target name="prepare">

<mkdir dir="${build.dir}"/>

</target>

<target name="war" depends="prepare"

description="creates WAR file">

<war destfile="${war.file}" webxml="${web.dir}/web.xml">

<fileset dir="${groovy.dir}"/>

<lib file="${groovy.jar}"/>

<lib file="${asm.jar}"/>

</war>

</target>

<target name="deploy" depends="war"

description="deploys WAR file">

<delete dir="${webapps.dir}/${ant.project.name}"/>

<delete file="${webapps.dir}/${war.file}"/>

<copy file="${war.file}" todir="${webapps.dir}"/>

</target>

</project>

在这个Groovlet例子被部署了之后, 你可以让它在你浏览器中显示出来通过访问如下的地址http://localhost:8080/GroovletExample/SimpleGroovlet.groovy. GroovletExample是网络应用程序的名字. SimpleGroovlet.groovyGroovlet的名字.这是与web.xml文件中的GroovyServlet指定的url-pattern相对应的.

Issues

Groovy还不算完美.浏览关于Groovy的文章,请访问http://groovy.codehaus.org/ 并点击Issue Tracker连接.下面是一些发表了的文章以及其编号.

· Primitive parameters to methods and closures aren't supported yet (128 & 133).

· Arrays of primitives aren't supported yet (119).

· Static primitive fields aren't supported yet (153).

· Chained assignment (x = y = 19) isn't supported yet (57).

· * imports aren't supported yet (84).

· Compiler doesn't catch calls to non-existent methods on statically typed parameters (170).

· Nested classes aren't supported yet (69).

总结

我们已经快速的浏览了Groovy的一些语法和特性.这些基于Java的捷径让你完成了更多的工作吗? 你在工作中找到了更多乐趣吗?你的代码是变得更容易理解还是更难了?我希望可以看到你们的反馈. 给我发Email mark@ociweb.com. 同时你也可以在Groovy邮件列表中分享你的反馈在这里.

参考书目

Groovy的主页 - http://groovy.codehaus.org/

分享到:
评论

相关推荐

    grpcio-1.44.0-cp39-cp39-manylinux2010_x86_64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    grpcio-1.42.0-cp38-cp38-macosx_10_10_x86_64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    江西省抚州市信通网络科技有限公司主页图标修正版

    各页面加入图标 新网站,新气象。

    C评级客户流失率相对误差.jpg

    C评级客户流失率相对误差

    tensorflow-2.9.3-cp39-cp39-win-amd64.whl

    python爬虫数据可视化

    Python初级贪吃蛇代码

    内容概要: 简单的贪吃蛇游戏,拓展、可移植性高。 适用人群: 不限。 使用场景: 不限。

    cryptography-38.0.0-cp36-abi3-manylinux_2_24_x86_64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    笔记本显卡RTX 4060 GPU 驱动程序

    笔记本显卡RTX 4060 GPU 驱动程序

    LCD取模软件PCtoLCD2002和Image2Lcd 2.9

    LCD取模软件PCtoLCD2002和Image2Lcd 2.9

    aTrustInstaller.pkg

    Mac系统aTrust客户端-2.3.10-SP4

    grpcio-1.37.0-cp39-cp39-manylinux2010_x86_64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    基于协同过滤、矩阵分解、gvdt+lr、wide&deep等算法的推荐模型python实现源码含项目说明+数据集.zip

    【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于协同过滤、矩阵分解、gvdt+lr、wide&deep等算法的推荐模型python实现源码含项目说明+数据集.zip 推荐算法的实现,python、jupyter双版本,详尽注释。 正在努力更新中... #### 对MovieLens电影评分小型数据集做Top N推荐: 0. baseline--推荐最热门的N=20部电影,precision=11%, recall=4%, coverage=0.2%, popularity=169。这部分内容包含在UserCF.py 1. UserCF,precision=25%, recall=10%, coverage=10%, popularity=4.4 2. ItemCF,precision=26%, recall=10%, coverage=15%, popularity=4.3 #### 对MovieLens电影评分小型数据集做评分预测: 0. baseline--使用所有评分的均值做预测,MAE:0.83。这部分内容包含在LinearRegression_Rating.ipynb 1. BiasSVD,MAE:0.68 2. LinearRegression,MAE:0.61 #### 对criteo广告展示小型数据集做点击率预测 1. gbdt+lr,binary_logloss:0.4783 #### 对Census数据中的收入做二分类 0. Google TensorFlow Guide上的Wide&Deep基准模型准确率: 0.83。(从有的知乎博主分享的链接来看,已经打不开了) 1. Wide&Deep, accuracy: 0.8587

    基于C++实现的连接池、线程池、内存池、对象池项目源码含项目说明.zip

    【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于C++实现的连接池、线程池、内存池、对象池项目源码含项目说明.zip ## CPP连接池 ### 关键技术点 MySQL数据库编程、单例模式、queue队列容器、C++11多线程编程、线程互斥、线程同步通信和 unique_lock、基于CAS的原子整形、智能指针shared_ptr、lambda表达式、生产者-消费者线程模型 ## CPP线程池 ### 关键技术点 作为五大池之一(内存池、连接池、线程池、进程池、协程池),线程池的应用非常广泛,不管是客户 端程序,还是后台服务程序,都是提高业务处理能力的必备模块。有很多开源的线程池实现,虽然各自 接口使用上稍有区别,但是其核心实现原理都是基本相同的。 ## CPP内存池 ### 关键技术点 读一下STL和nginx的内存池实现,并且单单的内存池的地方项目提取出来,方便后面对于不同类型的内存池进行分析 ## 对象池 ### 关键技术点 对于new和delete,malloc和free的源码进行阅读,对于创建对象需要多次创建和释放的的情况实现一个对象池 实现的方案使用Queue进行创建

    Maven是一个项目管理和构建自动化工具

    maven安装与配置

    基于html的六一儿童节祝福网页

    基于html的六一儿童节祝福网页,这个页面展示了一个简洁的儿童节祝福界面,包含一个标题、祝福文字和几张示例图片。你可以根据需要替换示例图片的链接和文字内容。

    基于Python实现的车牌检测和识别系统

    车牌检测和识别项目介绍 车牌的检测和识别的应用非常广泛,比如交通违章车牌追踪,小区或地下车库门禁。在对车牌识别和检测的过程中,因为车牌往往是规整的矩形,长宽比相对固定,色调纹理相对固定,常用的方法有:基于形状、基于色调、基于纹理、基于文字特征等方法,近年来随着深度学习的发展也会使用目标检测的一些深度学习方法。该项目主要的流程如下图所示: 1.输入原始图片,通过二值化,边缘检测,和基于色调的颜色微调等办法检测出原图中的车牌号的位置; 2.把检测到的车牌(ROI)裁剪,为车牌号的识别做准备; 3.基于裁剪的车牌号,使用直方图的波峰波谷分割裁剪的车牌号(如上图中的第3步) 4.训练机器学习模型做车牌识别,这里训练了2个SVM,一个SVM用来识别省份简称(如 鲁),另一个SVM用来识别字母和数字。 5.通过PyQt5把整个算法封装成GUI程序,并打包发布安装软件。

    超市积分管理系统的设计与实现

    本文从超市会员管理的实质入手,从本质区别超市会员管理与其他商业消费的会员管理的根本区别,针对专一积分管理提出看法,希望让系统更适用于商业超市的发展。让积分制度实施在一个合适的领域内,并不是所谓的通用格式,而是一个适合超市的专属模式。因此设计开发一种适合超市使用的会员积分管理系统可以实效得解决问题,能够让超市的会员真实的感受到会员积分带来的好处。 本系统是专门设计适用于超市的会员积分管理系统。整体采用B/S架构开发,通过对系统深入细致的分析,以及对业务背景和需求的了解,结合流行成熟的Web开发技术J2EE,设计搭建双管理权限。系统的总体技术框架为JSP+Servlet+JavaBean。前台浏览器浏览,后台服务器直接连接SQL Server2000数据库。通过各客户端计算机接入会员积分的各项事务,实现积分管理的规范性和安全性。同时作为会员信息管理系统的组成部分,将来可以有很好的扩展性和通用性。

    2022年中兴1.5.0 内附教程

    2022年中兴1.5.0 内附教程 应该是中兴22年下半年之前的光猫,自己看教程。

    matlab仿真:智能微电网PSO优化算法

    matlab仿真程序,智能微电网PSO优化算法

    iOS Object-c 实现界面横竖屏切换源代码

    iOS Object-c 实现界面横竖屏切换源代码

Global site tag (gtag.js) - Google Analytics