Groovy与Java的比较(上)
java.io
java.math
java.net
java.util
groovy.lang
groovy.util
3.断言不支持jvm的-ea参数进行开关
4.支持对对象进行布尔求值
5.类不支持default作用域,且默认作用域为public
6.受检查类型异常(Checked Exception)也可以不用捕获
7.一些新的运算符
8.groovy中基本类型也是对象,可以直接调用对象的方法,如:
- assert (-12345).abs() == 12345
但浮点运算是基于BigDecimal类
- assert 0.25 instanceof BigDecimal
- assert 0.1 * 3 == 0.3
- assert 1.1 + 0.1 == 1.2
- assert 1 / 0.25 == 4
Groovy与Java的比较(中)
9.字符串的处理
String对象和java类似,但没有character的概念,没有迭代每个字符的方法。
使用单引号定义普通字符串,双引号定义的字符串可以包含Groovy运算符,$符号则需要转义("\$"),如:
- String name = "Ben"
- String greeting = "Good morning,${name}"
- assert greeting == 'Good morning,Ben'
- String output = "The result of 2 + 2 is: ${2 + 2}"
- assert output == "The result of 2 + 2 is: 4"
还可以使用三个连续的"来定义多行字符串,如:
- String getEmailBody(String name) {
- return """Dear ${name},
- Thank you for your recent inquiry. One of our team members
- will process it shortly and get back to you. Some time in
- the next decade. Probably.
- Warmest and best regards,
- Customer Services
- """
- }
char类型的使用方法:
- char ch = 'D'
- assert ch instanceof Character
- String str = "Good morning Ben"
- str = str.replace(' ' as char,'+' as char)
- assert str == "Good+morning+Ben"
10.as运算符,用于没有集成关系的类型间强制类型转换,如:
- assert 543667 as String == "543667"
- assert 1234.compareto("34749397" as int) < 0
可通过实现asType(Class) 方法来实现自定义的as行为,默认的方法包括:
11.一些集合类型的语法甜头(Syntax sugar for lists,maps,and ranges)
从语言层面支持List\Map\Range类型,而不是通过SDK中的类
使用[]创建创建和初始化List、Map,如:
- List myList = [ "apple","orange","lemon" ]
- Map myMap = [ 3: "three",6: "six",2: "two" ]
- assert 3 == [ 5,6,7 ].size()
- List numbers = [ 5,10,15,20,25 ]
- assert numbers[0] == 5 //获取List中的对象
- assert numbers[3] == 20
- assert numbers[-1] == 25 //逆序获取List对象
- assert numbers[-3] == 15
- numbers[2] = 3 //更新List对象
- assert numbers[2] == 3
- numbers < < 30 //添加数据
- assert numbers[5] == 30
- Map items = [ "one": "apple",
- "two": "orange",
- "three": "pear",92); word-break:normal; border-top:medium none; border-right:medium none; padding-top:0px!important"> "four": "cherry" ]
- assert items["two"] == "orange" //从Map中获得对象
- assert items["four"] == "cherry"
- items["one"] = "banana" //更新Map中对象
- assert items["one"] == "banana"
- items["five"] = "grape" //增加对象到中
- assert items["five"] == "grape"
新的类型:Range
Range实现了java.util.List,可以作为List使用,并扩展了包含(..)和排除(..< )运算符
- // an inclusive range
- def range = 5..8
- assert range.size() == 4
- assert range.get(2) == 7
- assert range[2] == 7
- assert range instanceof java.util.List
- assert range.contains(5)
- assert range.contains(8)
- // lets use an exclusive range
- range = 5..< 8
- assert range.size() == 3
- assert range.get(2) == 7
- assert range[2] == 7
- assert range instanceof java.util.List
- assert range.contains(5)
- assert ! range.contains(8)
- //get the end points of the range without using indexes
- def range = 1..10
- assert range.from == 1
- assert range.to == 10
- List fruit = [
- "apple",
- "pear",92); word-break:normal; border-top:medium none; border-right:medium none; padding-top:0px!important"> "lemon",
- "orange",92); word-break:normal; border-top:medium none; border-right:medium none; padding-top:0px!important"> "cherry" ]
- for (int i in 0..< fruit.size()) { //Iterates through an exclusive range B
- println "Fruit number $i is '${fruit[i]}'"
- }
- List subList = fruit[1..3] //Extracts a list slice C
12.一些省时的特性
行末的分号(;)不是必须的。在没有分号的情况下,groovy计算一行如果是有效的表达式,则认为下一行是新的表达式,否则将联合下一行共同作为一个表达式。分隔多行的表达式,可以用/符号,如:
- String fruit = "orange,apple,pear," \
- + "banana,cherry,nectarine"
方法调用时的圆括号()不是必须的(但建议保留)。但在无参方法调用,或第一个参数是集合类型定义时还是必须的:
- println "Hello,world!"
- println()
- println([1,2,3,4])
方法定义中的return语句不是必须的,没有return的情况下,将返回方法体中最后一行的值,如下面的方法返回value+1:
int addOne(int value) { value + 1 }
Groovy与Java的比较(下)
13.语言级别的正则表达式支持
使用斜线(/)定义正则表达式,避免java中的多次转义,如"\\\\\\w"相当于/\\\w/。
如果要作为java中的Pattern对象使用,可以使用~符号表示,如:
- assert ~"London" instanceof java.util.regex.Pattern
- assert ~/\w+/ instanceof java.util.regex.Pattern
使用=~运算符进行匹配
- assert "Speaking plain English" =~ /plain/
使用==~运算符进行精确匹配
- assert !("Speaking plain English" ==~ /plain/)
- assert "Speaking plain English" ==~ /.*plain.*/
捕获分组,如:
- import java.util.regex.Matcher
- String str = "The rain in Spain falls mainly on the plain"
- Matcher m = str =~ /\b(\w*)ain(\w*)\b/
- if (m) {
- for (int i in 0..< m.count) {
- println "Found: '${m[i][0]}' - " +
- "prefix: '${m[i][1]}'" +
- ",suffix: '${m[i][2]}'"
- }
- }
输出:
- Found: 'rain' - prefix: 'r',suffix: ''
- Found: 'Spain' - prefix: 'Sp',suffix: ''
- Found: 'mainly' - prefix: 'm',suffix: 'ly'
- Found: 'plain' - prefix: 'pl',suffix: ''
14.简化的javabean
属性定义不需要setter/getter。未指定作用域的属性,groovy自动认为是private并生为其成setter/getter,也可以根据需要进行覆写。如下除了最后一个字段,都是属性:
- class MyProperties {
- static String classVar
- final String constant = "constant"
- String name
- public String publicField
- private String privateField
- }
简化bean的初始化,可以使用Map进行初始化,或键值对的方法,如
- DateFormat format = new SimpleDateFormat(
- lenient: false,
- numberFormat: NumberFormat.getIntegerInstance(),
- timeZone: TimeZone.getTimeZone("EST"))
可以使用属性的方式读取map:
- Map values = [ fred: 1,peter: 5,glen: 42 ]
- assert values.fred == 1
- values.peter = 10
- assert values.peter == 10
注:groovy将map的key作为字符串处理,除非是数字或者用圆括号包含。这里的fred就是字符串"fred",但引号不是必须的,只有在key包含空格、句点或其他不能作为Groovy标示符的字符存在时才需要。如果需要使用一个变量的值作为key,则使用圆括号,如 [ (fred): 1 ]。
15.groovy不具备的java特性
不能用单引号定义字符类型,但可以使用as运算符将一个字母的字符串转换为字符类型
for循环中不能用逗号分隔多个运算符,如下面的代码是不允许的:
- for (int i = 0,j = 0; i < 10; i++,j++) { ... }
不支持DO...WHILE循环,但可以使用while...for运算代替
16.groovy的重要特性——闭包:
可以看作一个匿名方法定义,可以赋予给一个变量名、作为参数传递给方法调用、或者被方法返回。也可以想象为只有一个方法定义的匿名类。
闭包的语法{ < arguments> -> < body> },如:
注:sort方法只有一个闭包类型的参数,省略了圆括号;闭包中使用了默认的return值
当没有参数传入时,仍然需要保留箭头的存在{-> ... }
只有一个参数传入时,可以省略箭头,隐式的创建一个it参数,引用当前对象,如:
- [ "apple","cherry" ].each { println it }
可以将闭包赋予一个变量,如
只有一个参数的闭包,可以不传入参数,运行时隐式的传入null参数
- List list = [ 1,5,6 ]
- list.inject(0,{ runningTotal,value -> runningTotal + value })
可以这样写:
- assert 15 == list.inject(0) { runningTotal,value -> runningTotal + value }
便于闭包中具有多行时代码更加清晰
不要滥用闭包。当闭包作为一个属性时,不要在子类中覆写,实在需要这样做,使用方法。使用闭包也无法利用java中很多AOP框架的特性
17.groovy的重要特性——动态编程
- def sortPeople(people,property) {
- people.sort { p1,p2 -> p1."${property}" < => p2."${property}" }
- }
- peopleList.sort()
- peopleList."sort"()
动态类型(duck typing:"if it walks like a duck and talks like a duck,it’s probably a duck):运行期解析对象的属性和方法,允许在运行时增加对象的属性和方法而不修改源代码,因此可能出现调用未定义方法的情况。
动态编程带来的危险:
编译器不能检查到类型错误、方法或属性的错误调用,应该养成编写测试的习惯
难以调试,使用“单步跳入(step into)”经常进入一些反射中,使用“运行到光标处(run to cursor)”代替
动态的类型定义使代码难以阅读,使用良好的命名、注释,尽量明确定义变量类型,便于IDE检测ht potential type errors in the call潜在的错误。
18.Groovy JDK中的增强
Collection/Array/String具有size()方法
Collection/Array/String具有each(closure)方法,方便的进行遍历
Collection/Array/String具有find(closure)、findAll(closure)方法,find返回第一个符合条件的对象,findAll返回所有符合条件对象列表,如:
- def glen = personList.find { it.firstName == "Glen" }
Collection/Array/String具有collect(closure)方法,对集合中每个对象执行一段方法后,返回结果集,如:
- def names = [ "Glen","Peter","Alice","Graham","Fiona" ]
- assert [ 4,5 ] == names.collect { it.size() }
Collection/Array/String具有sort(closure)方法,包括:
一个参数的闭包,如:
两个参数的闭包,如:
Collection/Array具有join(String)方法
assert "Glen,Peter,Alice,Fiona" == names.join(",")
File.size()方法返回文件的byte值,相当于File.length()方法
File.withWriter(closure)方法,从文件创建一个Writer对象传给闭包,闭包执行完毕后,依赖的输出流自动安全关闭。另外还有若干with...方法查看文档
Matcher.count返回相应Matcher的匹配数量
Number.abs()方法,对数字求绝对值
Number.times(closure)执行n次闭包,将当前执行的次数作为参数传给闭包
19.XML的处理
示例的XML:
- < root>
- < item qty="10">
- < name>Orange< /name>
- < type>Fruit< /type>
- < /item>
- < item qty="6">
- < name>Apple< /name>
- < item qty="2">
- < name>Chair< /name>
- < type>Furniture< /type>
- < /item>
- < /root>
处理程序
- import groovy.xml.MarkupBuilder
- import groovy.util.XmlSlurper
- def file = new File("test.xml")
- def objs = [
- [ quantity: 10,name: "Orange",type: "Fruit" ],92); word-break:normal; border-top:medium none; border-right:medium none; padding-top:0px!important"> [ quantity: 6,name: "Apple",
- [ quantity: 2,name: "Chair",type: "Furniture" ] ]
- def b = new MarkupBuilder(new FileWriter(file)) 创建MarkupBuilder对象
- b.root {
- 动态调用root方法,但builder对象并没有该方法,把它作为一个新的XML对象的根节点,并且把方法名作为根节点名称
- objs.each { o ->
- item(qty: o.quantity) {
- name(o.name)
- type(o.type)
- }
- }
- }
- 遍历集合,创建节点,其中item/name/type也是动态的方法,以方法名作为节点名,方法参数作为节点的属性
- def xml = new XmlSlurper().parse(file)
- 使用XmlSlurper对象解析内存中的XML文件
- assert xml.item.size() == 3
- assert xml.item[0].name == "Orange"
- assert xml.item[0].@qty == "10"
- 使用动态的属性名读取XML节点
- 使用@字符读取节点属性
- println "Fruits: ${xml.item.findAll {it.type == 'Fruit'}*.name }"
- println "Total: ${xml.item.@qty.list().sum {it.toInteger()} }"
20.最佳实践
使用地道的Groovy语法:尽可能使用groovy中简化后的语法风格,减少代码量
实验:使用groovy console或shell可以方便的实验groovy代码
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。