Groovy与Java的比较(上)
网站建设哪家好,找创新互联!专注于网页设计、网站建设、微信开发、重庆小程序开发、集团企业网站建设等服务项目。为回馈新老客户创新互联还提供了新县免费建站欢迎大家使用!
1.支持函数式编程,不需要main函数
2.默认导入常用的包,包括:
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\Map支持数组风格的用法
- 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",
- "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",
- "lemon",
- "orange",
- "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
直接使用“.属性名”的方法代替getter,如:
- Date now = new Date()
- println "Current time in milliseconds: ${ now.time }"
- now.time = 103467843L
- assert now.time == 103467843L
属性定义不需要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> },如:
- List fruit = [ "apple", "Orange", "Avocado", "pear", "cherry" ]
- fruit.sort { String a, String b -> a.compareToIgnoreCase(b) }
- println "Sorted fruit: ${fruit}"
注:sort方法只有一个闭包类型的参数,省略了圆括号;闭包中使用了默认的return值
当没有参数传入时,仍然需要保留箭头的存在{-> ... }
只有一个参数传入时,可以省略箭头,隐式的创建一个it参数,引用当前对象,如:
- [ "apple", "pear", "cherry" ].each { println it }
可以将闭包赋予一个变量,如
- Closure comparator = { String a, String b ->
- a.compareToIgnoreCase(b)
- }
- List fruit = [ "apple", "Orange", "Avocado", "pear", "cherry" ]
- fruit.sort(comparator)
- println "Sorted fruit: ${fruit}"
- assert comparator("banana", "Lemon") < 0
只有一个参数的闭包,可以不传入参数,运行时隐式的传入null参数
当闭包是一个方法的最后一个参数时,可以写在圆括号外面,如:
- List list = [ 1, 3, 5, 6 ]
- list.inject(0, { runningTotal, value -> runningTotal + value })
可以这样写:
- assert 15 == list.inject(0) { runningTotal, value -> runningTotal + value }
便于闭包中具有多行时代码更加清晰
不要滥用闭包。当闭包作为一个属性时,不要在子类中覆写,实在需要这样做,使用方法。使用闭包也无法利用java中很多AOP框架的特性
17.groovy的重要特性——动态编程
动态的使用属性,如下的java代码:
- public void sortPeopleByGivenName(List< Person> personList) {
- Collections.sort(personList, new Comparator< Person>() {
- public int compare(Person p1, Person p2) {
- return p1.getFamilyName().compareTo(p2.getFamilyName());
- }
- } ) ;
- }
可使用下面的代替,当需要使用其他字段比较时,不需要修改代码
- def sortPeople(people, property) {
- people.sort { p1, p2 -> p1."${property}" < => p2."${property}" }
- }
将一个String作为属性或方法名进行调用,如:
- 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, 5, 6, 5 ] == names.collect { it.size() }
Collection/Array/String具有sort(closure)方法,包括:
一个参数的闭包,如:
- def names = [ "Glen", "Peter", "Ann", "Graham", "Veronica" ]
- def sortedNames = names.sort { it.size() }
- assert [ "Ann", "Glen", "Peter", "Graham", "Veronica" ] == sortedNames
两个参数的闭包,如:
- def names = [ "Glen", "Peter", "Ann", "Graham", "Veronica" ]
- def sortedNames = names.sort { name1, name2 ->
- name1.size() < => name2.size()
- }
- assert [ "Ann", "Glen", "Peter", "Graham", "Veronica" ] == sortedNames
Collection/Array具有join(String)方法
- def names = [ "Glen", "Peter", "Alice", "Fiona" ]
- assert "Glen, Peter, Alice, Fiona" == names.join(", ")
File.text属性读取文件内容作为字符串返回
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>
- < type>Fruit< /type>
- < /item>
- < 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" ],
- [ quantity: 6, name: "Apple", type: "Fruit" ],
- [ 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代码
尽可能使用方法,而不是闭包。方法易于理解,也利于和java交互
在方法签名中尽可能的使用确定的类型,便于代码阅读和IDE的错误检测。在使用动态类型时要有清晰完善的文档注释
网站栏目:比较与分析Groovy与Java
当前路径:http://www.gawzjz.com/qtweb/news47/193097.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联