grails学习笔记——Groovy与java的比较

grails学习笔记——Groovy与java的比较

1.支持函数式编程,不需要main函数
2.默认导入常用的包,包括:

  • java.io  
  • java.math  
  • java.net  
  • java.util  
  • groovy.lang  
  • groovy.util 
3.断言不支持jvm的-ea参数进行开关
4.支持对对象进行布尔求值
TypeEvaluates to false
Boolean  false, Boolean.FALSE
Object referencenull
Number 0
String, GStringZero-length string
CollectionEmpty Collection
MapEmpty Map
IteratorhasNext() returns false
EnumerationhasMoreElements() returns false
java.util.regex.Matcherfind() returns false
5.类不支持default作用域,且默认作用域为public
6.受检查类型异常(Checked Exception)也可以不用捕获
7.一些新的运算符
运算符用法相当于JAVA
?.f (obj?.value != null) {
    . . .
}
if (obj != null && obj.value != null) { 
    . . . 
}
?: 
String name = person.getName() ?: "<unknown>"String name = (person.getName() != null) ? person.getName() : "<unknown>"
*. 
List names = people*.nameList names = new ArrayList();
for(Iterator it = people.iterator();it.hasNext();){
    People people = (People)it.next();
    names.add(people.getName());
}
<=>public int compare(int i1, int i2) { 
    return i1 <=> i2; 
}
public int compare(int i1, int i2) { 
    if (i1 == i2) return 0; 
    else if (i1 < i2) return -1; 
    else return 1; 
}
==String str = null 
assert str == null 
assert str != "test" 

str = "test" 
assert str != null 
assert str == "test" 
str += " string" 
assert str == "test string"
相当与equals方法,如果左侧的对象实现了compareTo方法,则调用compareTo方法且返回0时,返回true.而对象的比较则要调用is方法,如:
BigDecimal x = 0.234 
BigDecimal y = x 
assert y.is(x) 
assert !y.is(0.234) 
assert y == 0.234
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
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行为,默认的方法包括:
源类型
目标类型
说明
StringNumber (int, double, Long,BigDecimal, and so on)转换成相应的数字类型,如果字符串不是数字,则抛出NumberFormatException
ListArray将List转换成Array,如myList as String[]
List 或 arraySet将List或array直接转换为setb
任意对象
boolean使用groovy的布尔运算逻辑进行求值
CollectionList复制原始collection中的对象创建一个List,对象在List中的顺序由原collection的迭代顺序决定
StringList将字符串转换为每个字符的序列,并放到List中
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 } 
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的错误检测。在使用动态类型时要有清晰完善的文档注释

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值