G&GR翻译之旅——从Java到Groovy(2-新的和改进的语法元素,结构和句法结构)

新的和改进的语法元素,结构和句法结构
        一方面,Groovy添加新的语法元素、循环结构和语言级构建器;一方面,改进已有Java语法元素和结构,以提高其易用性。接下来,将详细讨论Groovy中一些常用的语法。
语言级断言(Assertions)
        您一定注意到前面多数例子都用到assertion。事实上,为编写本书实例代码,断言的确帮了我很大的忙,因为它可广泛应用于判断结果输出的正确性,因此编写代码实例变得简单。断言也是学习、体验Groovy的最佳途径。断言通常用于编写自校验码(self- checking code),显示当前程序的状态,并起到解释代码的作用。然而,他们比单纯的代码注释显得更加有用,这是因为因为代码运行时断言也随着被执行。同样的原因,断言也要比利用输出语句(print statements)把输出结果打印到控制台要有效得多。清单2.4给出了断言的一个例子。
        清单2.4 断言(Assertions)的应用
        x = 1
        assert x // x must be not null
        assert (x==1)
        assert ['a']  // A list must be nonempty
        assert ['a':1] // A map must be nonempty
        assert 'a' // A String must be nonempty
        assert 1 // A number must not be equal to zero
        assert !null // Null will always fail
        assert true // A true Boolean value returns true

        从清单中您可发现,Groovy的断言要比Java中的assert关键字要功能强大得多,原因是Groovy断言能接受任何类型,而Java断言只能用于Boolean条件而已。Groovy会按照一定规则将非布尔型对象强制为布尔值:空集合和字符串,零,空对象均被转型为false;反之为true。
        Java中的断言可以被禁用,而Groovy断言则相反,他们能被执行,不会被禁用。
如果Groovy中断言失败,程序会会抛出一条的错误信息,如:
        a = [1,2,3]
        assert a.size() == 2, "list ${a} must be of size 2"

        运行上面的代码会出现错误,并会抛出如下信息:
        Exception thrown: java.lang.AssertionError:list [1,2,3] must be of size 2.
        Expression: (a.size() == 2)

闭包(Closure)
        简单地说,闭包是一个能被传递和执行的代码块。闭包可有参数、返回值,可引用其他变量等等。闭包定义方式为:
        {arg1, arg2 .. -> statements}
        “->”字符用来分离可选参数列表(the optional arguments)和闭包代码体(statements)。
        尽管闭包的概念及语法在Java开发者看来是陌生的,但总的来说闭包还是容易学习可立即上手的。闭包的很多高级应用将会在第5章详细介绍。本节只是简单介绍一下闭包,让您对它有所了解。
        清单2.5显示如何使用闭包的一个简单例子。
        清单2.5 闭包的应用
        //Simple closure with no arguments
        def clos1 = { println "hello world!" }
        //Calling the closure
        clos1()

        //A closure with arguments
        def clos2 = {arg1,arg2 -> println arg1+arg2}
        clos2(3,4)

        //A closure defined inside a method. The closure is bound to the
        //variables within its scope
        def method1(book){
            def prefix = "The title of the book is: "
            return {println prefix + book}
        }

        def clos3 = method1("Groovy")
        clos3()

        您或许会问,闭包与Java方法到底存在怎样的差别呢?是这样的,闭包是匿名的代码块,它可以在类或方法外声明,只在被调用时才被执行。闭包通常被赋给一个变量,可看作这个闭包的标识符,并通过它来调用闭包。闭包真正强大的功能就是该变量能在程序中传递,这就意味着您可以编写以闭包作为参数的闭包和方法。
        为了更好说明问题,看下面这个例子,类Emloyee只有一个calculateRaise方法,该方法以闭包为参数,来计算如何给雇员加薪。例如,您想给某些员工薪水提高50%,而另一部分员工只加薪300美元。代码详见清单2.6。
        清单2.6 闭包为方法参数的例子
        public class Employee{
            def salary
            public double calculateRaise(c){
                return c(salary)
            }
        }

        Employee employee1 = new Employee(salary:1000)
        def raise1 = {salary -> (salary * 1.5)}
        assert employee1.calculateRaise(raise1) == 1500

        Employee employee2 = new Employee(salary:500)
        def raise2 = {salary -> (salary + 300)}
        assert employee2.calculateRaise(raise2) == 800

        如果用Java编写上述代码,您很可能要定义一个Raise接口,该接口只有一个calculateRaise方法。然后创建两个Raise接口实现,并且实现calculateRaise方法。最后,创建Employee类,并且含有一个以Raise实例作为参数的方法,然后调用calculateRaise方法。然而相比较而言,Groovy的实现方式更简单直接,不需要引入太多的数据类型。可以这么说,如果使用了闭包,您将很少用得到接口了。
集合数据类型(Collective Data Types)
        第一章曾提到,Groovy最强大的特性之一便是对集合语言级支持,包括列表(lists),映射(maps)和范围(ranges)。其中,列表和映射是Java程序员最熟悉不过的了,然而在Groovy中显得更强大和灵活;范围是Java中不存在的新数据结构。下面将简单介绍这些集合的新句法结构,具体地将在第3章进行讨论。
列表(Lists)
        Groovy中列表的语法类似于Java中的数组,但是不要被其外表所迷惑。Groovy列表远比Java数组强大,因为Java数组的长度固定,且不容易添加元素到数组中。Groovy中可按下面的方式定义列表:
        def a = [item1, item2, item3]
        数组的定义方式:
        def a = new Object[4] //必须制定数组的长度
        或:
        def a = [item1, item2, item3].toArray()
        集合中可以包含不同类型的元素,任何java.lang.Object的子类均可添加到列表中。下面代码在Groovy是正确无误的:
        a = ['Hi', 1, File]

        清单2.7展示了Groovy列表的基本应用。

        清单2.7 Groovy列表
        def a = [] //Empty list
        a += [1,2,3] //Adding elements to a list
        assert a == [1,2,3]
        assert a.size == 3
        a << 4 << 5 //Another way of adding elements to a list
        assert a == [1,2,3,4,5]
        a.add(6) //A third way of adding elements to a list
        assert a == [1,2,3,4,5,6]

        //Accessing elements of a list
        assert a[0] == 1 //Using a subscript
        assert a.get(0) == 1 //Using get
        assert a.getAt(0) == 1 //Using getAt
        assert a[-1]  == 6 //Last element index starts at -1 backwards

        //Modifying elements in a list
        a.putAt(1,1)
        assert a == [1,1,3,4,5,6]
        assert a.set(1,2) == 1 //Will return the old value
        assert a == [1,2,3,4,5,6]

        //Iterating over a list
        a.each{ println "$it"}
        //Printing items in a list with their index
        a.eachWithIndex{it, index -> println item : "$it", index : "$index"}

        //Removing items from a list
        a -= 1 //Remove number 1
        assert a == [2,3,4,5,6]
        a = a.minus([2,3,4]) //Remove the sublist [2,3,4]
        assert a == [5,6]

映射(Maps)
        映射,是一种将键(Key)映射到值(Value)的对象:一个映射不能包含重复的键;每个键只能映射到一个值。Groovy中定义映射方式为:
        def a = [key1:value1, key2:value2]
        键和值可以为任意类型。清单2.8为Groovy映射的基本应用

        //Creating a map
        def map = ['name':'Bashar','age':26,skills:['Java','Groovy'],         'author':true]
        assert map.size() == 4

        //Adding a key/value pair to a map
        map += ['city':'Tucson']
        assert map == ['name':'Bashar','age':26,skills:['Java','Groovy'],
               'author':true, 'city':'Tucson']
        //Alternative way of adding a key/value pair to a map
        map['state'] = 'AZ'
        assert map == ['name':'Bashar','age':26,skills:['Java','Groovy'],
               'author':true, 'city':'Tucson', 'state':'AZ']
        //Accessing map elements
        assert map.city == 'Tucson'
        assert map['city'] == 'Tucson'
        assert map.get('city') == 'Tucson'
        assert map.getAt('city') == 'Tucson'
        assert map.skills[0] == 'Java'

        //Keys are unique
        assert ['name':'Bashar','name':'Abdul'] == ['name':'Abdul']

        //Iterating over a map
        map.each{ it -> println it.key + ":" + it.value}
        map.eachWithIndex{ it, index -> println "item $index - " + it.key + ":" +         it.value}

范围(Ranges)
        Groovy语言级支持范围(Range)语法,并且可以指定是否包含边界值。从概念上讲,范围定义了由左边界值和右边界值指定的区间,并实现了如何从区间左边移到区间右边。范围可用于数值、字符串、日期,以及任何实现了Comprable接口并定义了next和previous方法的对象。按如下方式定义范围:
        def range = start ..end
        与其他结构结合使用时,范围会显得方便有效,尤其借助于范围的each方法。清单        2.9演示了如何使用Groovy中的范围。
        清单 2.9 Range的应用
        //Creating a range
        def range = 1..10
        assert range == [1,2,3,4,5,6,7,8,9,10]
        range = 'a'..'c'
        assert range == ['a','b','c']

        //Excluding the last element from a range
        range = 1..<8
        assert range == [1,2,3,4,5,6,7]

        //Using a range with each method
        (1..5).each{println it}

        //Using a range to create a list (slicing)
        assert [*1..4] == [1,2,3,4]
        assert [1,*2..4] == [1,2,3,4]

你可能感兴趣的:(java,数据结构,groovy,idea)