最近因为工作需要,接触groovy,很好的语言。以前学习过python,感觉没有用到的地方,现在用groovy有了深入学习的理由,和java的无缝衔接技术。
入门很简单,而且做了一个小脚本,比较几个数据库的表结构,将结果保存在excel中,用groovy代码才不到1K行,使用了POI,derby,oralce数据库等。不用创建很罗嗦的pojo,太好了。
这里就先整理一下基础的groovy东西。全部来自附件文档,然后自己粘贴出来而已。
字符串类型的方法:
- def firstname='Kate'
- def surname='Bush'
- //打印字符串的连接
- println firstname*2
- def fullname="$firstname $surname"
- println fullname
- println fullname-firstname
- //凑足15个字符,不够就在左边补充空格
- println fullname.padLeft(15)
- //关于字符串的截取
- println fullname[0..3]
- println fullname[-4..-1]
- //下面的方式比较特别,取第5个字符,以及3,2,1位置字符连接起来
- assert fullname[5,3..1]=='Beta'
- ff='aaaabbccadvbasd'
- lines=ff.split('a')
- //下面assert在后面表达式为false情况下抛出异常
- assert lines.size()==7
- //注意字符串中的特殊字符
- def plain='\n\r\t\b\\\f\$'
- assert plain.size()==7
- //关于字符串的闭包(注意下面的括号的使用方法!)
- fullname="${-> firstname} $surname"
- println fullname
- firstname = 'li'
- surname='shuiqing'
- println fullname
- //关于字符串的运算符
- fullname = fullname -'qing'-'l'+' hello world'
- assert fullname=='i Bush hello world'
- //字符串替换
- string = 'hippopotamus'
- assert string.replace('ppopotam','bisc') == 'hibiscus'
- //字符串反转,转换为list
- assert'apple'.toList() == ['a', 'p', 'p', 'l', 'e']
- //下面把字符串里面去掉重复数字,并排序.
- string = "an apple a day"
- assert string.toList().unique().sort().join() == ' adelnpy'
- //下面方法取出得到字符串里面的各个单词,并进行反转
- string = 'Yoda said, "can you see this?"'
- revwords= string.split(' ').toList().reverse().join(' ')
- assert revwords== 'this?" see you "can said, Yoda'
- println revwords
- //对数组进行筛选,找出反转之后还等于原来字符串并且长度大于5的字符串
- words = ['bob', 'alpha', 'rotator', 'omega', 'reviver']
- bigPalindromes= words.findAll{w-> w == w.reverse() && w.size() > 5}
- assert bigPalindromes== ['rotator', 'reviver']
- println bigPalindromes
数字方法:
- def x=3
- def y=4
- println x+y
- println x.plus(y)
- println x instanceof Integer //输出true
- def a=2/3
- //进行小数的取三位小数运算.
- def b = a.setScale(3,BigDecimal.ROUND_HALF_UP)
- assert b.toString() == '0.667'
- //进行不等于的比较
- println 4<=>3 //输出1
- 4!=3
- println 4**3 //4的3次方,等于4.power(3)
- println 4/3 //输出1.3333333333,等于4.div(3)
- println 8.intdiv(3) //输出1
- println 8%3 //取余,等于8.mod(3)
日期函数:
- import static java.util.Calendar.getInstance as now
- import org.codehaus.groovy.runtime.TimeCategory
- import java.text.SimpleDateFormat
- def date = new Date()+1
- println date
- input = '1998-06-03'
- df1 = new SimpleDateFormat("yyyy-MM-dd")
- date = df1.parse(input)
- df2 = new SimpleDateFormat("MMM/dd/yyyy")
- println 'Date was '+df2.format(date)
- println now().time
- println df1.format(now().time)
- //进行时间的计算
- use(TimeCategory){
- date3 = new Date()+1.year+3.hours-2.days
- println df1.format(date3)
- }
- /*
- Tue Apr 10 14:59:33 CST 2012
- Date was 六月/03/1998
- Mon Apr 09 14:59:33 CST 2012
- 2012-04-09
- 2013-04-07
- */
操作符重载:
- //下面演示对字符串实现了操作符++的重载.++对应的方法名是next
- for ( i='a';i<'d';i++)
- print i +", "
- println ''
- for( i in 'a'..'d')
- print i+", "
- //下面演示的对于集合,重载了操作符<<,对应的方法名是leftShift()
- lst = ['hello']
- lst << 'there'
- println lst
- //下面演示对一个自定义类实现的+的重载。
- class ComplexNumber{
- def real,imaginary
- def plus(other){
- new ComplexNumber(real:real+other.real,
- imaginary:imaginary+other.imaginary)
- }
- String toString(){
- "$real ${imaginary>0 ? '+':''}${imaginary}i"
- }
- }
- c1 = new ComplexNumber(real:1,imaginary:2)
- c2 = new ComplexNumber(real:4,imaginary:-31)
- println c1+c2
操作数据库
- import groovy.sql.Sql
- def testYear = '2011'
- //下面的Driver类找不到!修改配置文件就可以了。
- def sql = Sql.newInstance("jdbc:mysql://localhost:3306/dwz","root","123456"
- ,"com.mysql.jdbc.Driver")
- println '数据库名:'+sql.connection.catalog
- sql.execute("delete from testtable where name like ? or name like ? or name like ?",['ls%','lish%','%dataSet%'])
- println '插入我的数据之前,数据库:'
- sql.eachRow("select * from testtable"){
- println "id = ${it.id} year = ${it.name} "+it.name
- }
- println '--------------------------------------'
- wid = 123
- wname = 'lishuiqing'
- //下面必须使用双引号!
- sql.execute("insert into testtable(id,name) values (${wid},${wname})")
- sql.execute("update testtable set name =? where name = ?",['lsq','lishuiqing'])
- //下面使用预定义参数的查询语句
- sql.eachRow("select * from testtable where name like ?",["%a%"]){
- println "id = ${it.id} year = ${it.name} "+it.name
- }
- println '--------------------------------------'
- println '下面练习使用dataset'
- testtable = sql.dataSet('testtable')
- /*def anycity = testtable.findAll{ it.id>1 }
- anycity.each{
- println 1
- }*/
- 2.times{
- testtable.add(id:it,name:'使用dataSet添加'+it)
- }
- println "testtable.getSql():"+testtable.getSql()
- println '总行数:'+testtable.rows().size()
- num = 0
- testtable.each{
- //println it[0]----也可以输出指定位置的元素!!
- num = num+1
- println it.id+",year="+it.name
- }
- //注意要使用${}输出参数的话,必须使用双引号。。。
- println "${num}"
- println '--------------------------------------'
- println "下面显示当前数据库的运行实时状态"
- sql.eachRow("show status "){
- //下面在{}里面定义的变量,在外面也找到,也就是作用域是全部的范围!!
- if(it.variable_name=="Uptime")
- uptime = it[1]
- else if (it.variable_name =='Questions')
- questions = it[1]
- }
- println "数据库运行时间Uptime for Database:${uptime}"
- println "数据库查询的条目Number of Queries:${questions}"
- println "每分钟的查询条目Queties per Minutes = "+Integer.valueOf(questions)/Integer.valueOf(uptime)
- sql.eachRow("show status like 'Com_%'"){
- if(it.variable_name=="Com_insert")
- insertnum = Integer.valueOf(it[1])
- else if (it.variable_name == "Com_select")
- selectnum = Integer.valueOf(it[1])
- else if (it.variable_name == "Com_update")
- updatenum = Integer.valueOf(it[1])
- }
- println "查询语句有${selectnum},百分比:"+100*(selectnum/Integer.valueOf(uptime))+"%"
- println "插入语句有${insertnum},百分比:"+100*(insertnum/Integer.valueOf(uptime))+"%"
- println "更新语句有${updatenum},百分比:"+100*(updatenum/Integer.valueOf(uptime))+"%"
- println '--------------------------------------'
- println '下面将数据库里面的值保存到xml文件'
- bldr = new groovy.xml.MarkupBuilder()
- bldr.testtable{
- sql.eachRow('select * from testtable'){
- data(id:it.id,name:it.name)
- }
- }
- println bldr.text()
集合
- List
- assert [1,2,3,4] ==(1..4)
- //集合是有顺序的!!
- assert [1,2,3,4] !=[1,2,4,3]
- assert [1,2,3]+[1] ==[1,2,3,1]
- //将一个元素添加到已经存在的list中
- assert [1,2,3]<<1 ==[1,2,3,1]
- //从已有的list中删除元素
- assert [1,2,3,1]-[1] ==[2,3]
- assert [1,2,3]*2 ==[1,2,3,1,2,3]
- //flatten:扁平的意思
- assert [1,[2,3]].flatten() ==[1,2,3]
- assert [1,2,3].reverse()==[3,2,1]
- //测试两个集合是否有交叉
- assert [1,2,3].disjoint([4,5,6])
- //intersect:得到两个集合中的交集
- assert [1,2,3].intersect([4,3,1]) ==[3,1]
- //对集合进行循环处理
- assert [1,2,3].collect{it+3} ==[4,5,6]
- assert [1,2,3,1].unique().size()==3
- assert [1,2,3,1].count(1) ==2
- assert [1,2,3,4].min() ==1
- assert [1,2,3,4].max() ==4
- assert [1,2,3,4].sum() ==10
- assert [4,2,1,3].sort() ==[1,2,3,4]
- //对集合进行循环处理判断,并返回结果
- assert [4,2,1,3].findAll{it%2==0} ==[4,2]
- //对集合的迭代
- def expected = [1,2,3,'test']
- expected.each{test -> println test}
- Map:
- def map = [a:1,'b':2]
- println map //[a:1, b:2]
- println map.a
- println map['a']
- println map.keySet() //[a, b]
- map = [:]
- map[1] = 'a';map[2]='b'
- map[true] = 'p'
- map[false] = 'q'
- map[null]='x';map['null'] = 'z'
- assert map ==[1:'a',2:'b',(true):'p',(false):'q',(null):'x'
- ,'null':'z']
- //下面的例子很有用,对map进行了很快速的循环输出!!
- def sb = new StringBuffer();
- [1:'a',2:'b',3:'c'].each{k,v->sb << "$k:$v, "}
- //下面是输出字符串
- [1:'a',2:'b',3:'c'].each{k,v-> println "$k:$v, "}
- assert sb.toString() =='1:a, 2:b, 3:c, '
- //下面又是一种快速的输出map为字符串形式的方法
- map = [1:'a',2:'b',3:'c']
- def string = map.collect{k,v -> "$k:$v"}.join(', ')
- assert string == '1:a, 2:b, 3:c'
- //下面演示一个对city进行分类的例子
- assert [
- [name:'C',city:'London'],
- [name:'S',city:'London'],
- [name:'M',city:'LA'],
- [name:'Z',city:'HK'],
- [name:'A',city:'HK']
- ].groupBy{it.city}==[
- London:[ [name:'C',city:'London'],
- [name:'S',city:'London']],
- LA:[ [name:'M',city:'LA']],
- HK:[ [name:'Z',city:'HK'] ,
- [name:'A',city:'HK'] ]
- ]
- //map中顺序也是有关系的!顺序不对的map也不相等
- assert [ [name:1,city:'L'],[name:2,city:'H']] != [ [name:2,city:'H'],[name:1,city:'L']]
闭包
- 闭包的一个例子:
- import static java.lang.Math.*
- //闭包例子1
- piA = { 22/7 }
- piB = { 333/106 }
- piC = { 355/113 }
- piD = { 0.6*(3+sqrt(5))}
- piE = { 22/7 +37/47 +888/83}
- piF = { sqrt(sqrt(2143/22)) }
- //这里就是闭包的实际算法部分。
- howCloseToPI = { abs(it.value() - PI) }
- algorithms = ['piA':piA,'piB':piB,'piC':piC,'piD':piD,'piE':piE,'piF':piF]
- findBestPI(algorithms)
- def findBestPI(map){
- map.entrySet().sort(howCloseToPI).each{
- entry ->//下面调用了闭包的函数
- def diff = howCloseToPI(entry)
- println "Alorithm $entry.key differs by $diff"
- }
- }
- doubleNum = {num ->num*2}
- println doubleNum(3)
- //闭包例子2
- //下面的方法定义就是使用了闭包。传入了num,closure,其中closure是函数类型。
- processThenPrint = {num,closure->
- num = closure(num);println "num is $num"
- }
- //下面传入了函数名作为第二个参数
- processThenPrint(3,doubleNum)
- //下面传入第二个参数是匿名函数
- processThenPrint(10){it/2}
- //闭包例子3
- //下面又是一个闭包的例子
- def houston(Closure doit){
- (10..1).each{
- count -> doit(count)
- }
- }
- houston{ println it}
- //闭包例子4,用于迭代
- 3.times{println 'Hi'}
- [0,1,2].each{number -> println number}
- //注意下面的it!!
- [1,3,5].each{ println it}
- def println = {println it}
- [4,5,6].each println
- map = ['a':1,'b':2]
- map.each{key,value -> map[key]=value*2 }
- assert map == ['a':2,'b':4]
- //注意下面的each后面是小括号,不是大括号了!
- doubler = {key,value -> map[key] = value*2}
- map.each(doubler)
- assert map == ['a':4,'b':8]
- def doubleMethod(entry){
- map[entry.key] = entry.value *2;
- }
- doubler = this.&doubleMethod
- map.each(doubler)
- assert map == ['a':8,'b':16]
- //下面对集合的一些操作很容易的结合了闭包方法的使用
- //查询子元素
- assert [1,2,3].grep{it<3} ==[1,2]
- //判断是否有一个满足条件
- assert [1,2,3].any{ it%2==0 }
- //判断是否全部满足条件
- assert [1,2,3].every{ it <4}
- //将集合中全部元素join
- assert (1..9).collect{it}.join() == '123456789'
- assert (1..4).collect{it*2}.join() == '2468'
- //闭包例子5:新的函数curry!以及演示一个通过闭包将list进行修改的例子!!
- def add = {x,y -> x+y}
- def mult = {x,y -> x*y}
- assert add(1,3) == 4
- assert mult(1,3) == 3
- def min = {x,y -> [x,y].min()}
- def max = {x,y -> [x,y].max()}
- def sub = {x,y -> return 'x - y = '+(x-y)}
- //注意下面的curry函数,意思是默认的传入参数到原有的函数的第一个位置,并将结果返回为一个新的函数
- //例如下面的triple就是得到一个数值的三倍!!
- def triple = mult.curry(3);assert triple(2) ==6
- def atLeastTen = max.curry(10)
- def subTen = sub.curry(10)
- assert atLeastTen(5)==10
- assert atLeastTen(15) == 15
- assert subTen(13) == 'x - y = -3'
- //
- def pairWise(list ,invoke){
- if(list.size()<2) return []
- def next = invoke(list[0],list[1])
- return [next]+pairWise(list[1..-1],invoke)
- }
- assert pairWise(1..5,add) == [3,5,7,9]
- assert pairWise(1..5,mult) == [2,6,12,20]
- assert pairWise(1..5,min) == [1,2,3,4]
- assert pairWise(1..5,max) == [2,3,4,5]
- //inject--参数是初始值,然后放在一个闭包里面对list的每个元素进行迭代操作!
- assert 'cbaxabc' == ['a','b','c'].inject('x'){
- result,item -> item +result+item
- }
对xml的操作
- 对xml的解析
- def CAR_RECORDS = '''
- <records>
- <car name='HSV Maloo' make='Holden' year='2006'>
- <country>Australia</country>
- <record type='speed'>Production Pickup Truck with speed of 271kph</record>
- </car>
- <car name='P50' make='Peel' year='1962'>
- <country>Isle of Man</country>
- <record type='size'>Smallest Street-Legal Car at 99cm wide and 59 kg in weight</record>
- </car>
- <car name='Royale' make='Bugatti' year='1931'>
- <country>France</country>
- <record type='price'>Most Valuable Car at $15 million</record>
- </car>
- </records>
- '''
- //解析xml的第一步,进行分析--注意这里的找到的是根节点<records>,所以后面的car。size()就有值。
- def records = new XmlSlurper().parseText(CAR_RECORDS)
- //得到节点的数目
- assert 3 == records.car.size()
- //注意下面的得到car里面的country的条目,而不是直接进行records.country!!
- assert 3 == records.car.country.size()
- //depthFirst():计算全部的节点的数目
- assert 10 == records.depthFirst().collect{it}.size()
- def firstRecord = records.car[0]
- //得到一个节点里面的属性name
- assert 'car' == firstRecord.name()
- //得到一个节点里面的自定义属性,使用@属性名
- assert 'Holden' == firstRecord.@make.toString()
- //text():得到节点里面的文本信息!不是属性。
- assert 'Australia' == firstRecord.country.text()
- //对节点进行判断,找到make属性含有e的条目数量
- assert 2 == records.car.findAll {it.@make.toString().contains('e')}.size()
- //使用正则表达式进行节点筛选
- assert 2 == records.car.findAll{it.@make=~'.*e.*'}.size()
- //找到全部的国家符合正则表达式的record节点的make属性!
- assert ['Holden','Peel'] == records.car.findAll{ it.country =~ '.*s.*a.*'}
- .@make.collect{it.toString()}
- //找到全部的type非空的record节点的type属性!!
- assert ['speed','size','price'] == records.depthFirst().grep{it.@type!=''}.'@type'*.toString()
- def countryOne = records.car[1].country
- //查找父节点的两个方法!parent和使用路径表达式
- assert 'Peel' == countryOne.parent().@make.toString()
- assert 'Peel' == countryOne.'..'.@make.toString()
- //将所有的节点按照指定顺序排序之后,再按顺序输出name属性!注意后面的一个×号!
- def names = records.car.list().sort{ it.@year.toInteger()}.'@name'*.toString()
- assert ['Royale','P50','HSV Maloo'] == names
操作文件,属性文件:
- myFileDir = "d:\\"
- myFileName = 'mytest.txt'
- myFile = new File(myFileDir + myFileName)
- printFileLine = { println "File line:"+it}
- myFile.eachLine ( printFileLine )
- myFile.write('123')
- myFile.append('123')
- 读取属性文件:
- Properties properties = new Properties()
- properties.load(new FileInputStream("d:\\conf.properties"))
- println properties.getProperty("filename")
正则表达式:
- 正则表达式:
- assert 'Hello World!' =~ /Hello/
- assert 'Hello World!' ==~ /Hello\b.*/
- def p = ~/Hello\b.*/
- assert p.class.name == 'java.util.regex.Pattern'
- //下面的next方法是返回的下一个字符!
- assert "1.23".replaceAll(/./){ch-> ch.next()}== "2/34"
- assert "1.23".replaceAll(/\d/){num -> num.toInteger()+1}=='2.34'
- //下面的 == 不可以换行!否则就是语法错误!!为什么??因为每一行后面默认就是有一个分号的!!
- assert "1.23".replaceAll(/\d+/){num -