Groovy(七)-其他运算符

译文:Groovy Language Documentation
主目录见:Android高级进阶知识(这是总目录索引)

因为前段时间比较忙,所以[Android高级进阶]一直没更新,接下来有时间会重新更新,下一篇将会是热更新框架AndFix的完全解析,敬请期待...

今天算是运算符的最后一篇了,运算符的篇幅还真是很长,所以大家可想而知他的重要性!!!!

展开(spread)操作符
展开操作符(*.)会触发操作集合中的所有对象。相当于调用了遍历集合和合并结果到一个集合的操作。

class Car {
    String make
    String model
}
def cars = [
       new Car(make: 'Peugeot', model: '508'),
       new Car(make: 'Renault', model: 'Clio')]       1
def makes = cars*.make                                2
assert makes == ['Peugeot', 'Renault']                3

1.创建一个car对象的集合,这个list是一个集合对象。
2.调用展开操作符,访问每个对象的make属性。
3.返回make属性组成的集合和String集合的匹配

展开操作符是空安全的,这意味着如果集合中的元素是空的话,那么他就会返回null来代替抛出NullPointerException异常。

cars = [
   new Car(make: 'Peugeot', model: '508'),
   null,                                              1
   new Car(make: 'Renault', model: 'Clio')]
assert cars*.make == ['Peugeot', null, 'Renault']     2
assert null*.make == null                             3

1.建一个带有null元素的集合
2.使用展开操作符不会返回NullPointerException异常
3.如果接收者是null的,那么这种情况返回值就会是null

展开操作符可以用在任何实现了Iterable接口的类中:

class Component {
    Long id
    String name
}
class CompositeObject implements Iterable {
    def components = [
        new Component(id: 1, name: 'Foo'),
        new Component(id: 2, name: 'Bar')]

    @Override
    Iterator iterator() {
        components.iterator()
    }
}
def composite = new CompositeObject()
assert composite*.id == [1,2]
assert composite*.name == ['Foo','Bar']

展开的方法参数
有一些情况一个集合正好跟方法调用的参数匹配,在这个情况下,我们就可以使用展开操作符进行调用方法,例如,你想象一下你以下的方法签名:

int function(int x, int y, int z) {
    x*y+z
}

然后你有如下的集合:

def args = [4,5,6]

你就可以无需定义中间变量来调用方法:

assert function(*args) == 26

而且将展开的方法参数和普通的参数混合使用也是可以的:

args = [4]
assert function(*args,5,6) == 26

展开的集合元素
当被用在一个集合常量中,展开操作符就可以将集合元素内容内联到集合中:

def items = [4,5]                      1
def list = [1,2,3,*items,6]            2
assert list == [1,2,3,4,5,6]           3 

1.items是一个集合
2.我们想把items集合直接插入list中而无需调用addAll()方法
3.items集合的内容已经内联到list中了

展开的Map元素
展开Map元素操作符和展开List元素操作符的使用方式是一样的,但是对于Map来说,他允许你像下面这种方式来内联Map:

def m1 = [c:3, d:4]                   1
def map = [a:1, b:2, *:m1]            2
assert map == [a:1, b:2, c:3, d:4]    3

1.m1是我们要内联的元素
2.我们使用*:m1标记法来将m1内联进map中
3.map包含了所有m1的元素

展开Map操作符的位置是有关联的,就像下面的例子说明:

def m1 = [c:3, d:4]                   1
def map = [a:1, b:2, *:m1, d: 8]      2
assert map == [a:1, b:2, c:3, d:8]    3

1.m1是我们要内联的元素
2.我们使用*:m1操作符来展开m1的内容进map中,但是在展开d的时候重新定义了
3.map包含了所有的可能的键,但是d被重定义了

范围操作符
Groovy支持范围的概念而且提供了..来创建元素范围:

def range = 0..5                                    1
assert (0..5).collect() == [0, 1, 2, 3, 4, 5]       2
assert (0..<5).collect() == [0, 1, 2, 3, 4]         3
assert (0..5) instanceof List                       4
assert (0..5).size() == 6                           5

1.一个简单的integer类型范围,并且赋值给局部变量
2.一个IntRange包含了边界
3.一个IntRange不包含上边界
4.groovy.lang.Range实现了List
5.这意味着你可以使用size方法

Ranges的实现是轻量级的,只有下边界和上边界被保存,你可以从任何包含next()方法和previous()方法的Comparable对象来创建范围中的next / previous项,例如,你可以用下面这种方法来创建范围:

assert ('a'..'d').collect() == ['a','b','c','d']

<=>操作符
<=>代理了compareTo方法:

assert (1 <=> 1) == 0
assert (1 <=> 2) == -1
assert (2 <=> 1) == 1
assert ('a' <=> 'z') == -1

下标操作符
下标操作符是getAtputAt的简写标识,这取决于你是在一个赋值符号的左边还是右边来查找:

def list = [0,1,2,3,4]
assert list[2] == 2                         1
list[2] = 4                                 2
assert list[0..2] == [0,1,4]                3
list[0..2] = [6,6,6]                        4
assert list == [6,6,6,3,4]                  5

1.[2]可以用来替换getAt(2)
2.如果在赋值符的左边,将会调用putAt
3.getAt也支持范围
4.做putAt操作
5.list变化了

下标操作符是为了解构对象的一种getAt/putAt操作的自定义实现的一种简便方式。

class User {
    Long id
    String name
    def getAt(int i) {                                             1
        switch (i) {
            case 0: return id
            case 1: return name
        }
        throw new IllegalArgumentException("No such element $i")
    }
    void putAt(int i, def value) {                                 2
        switch (i) {
            case 0: id = value; return
            case 1: name = value; return
        }
        throw new IllegalArgumentException("No such element $i")
    }
}

def user = new User(id: 1, name: 'Alex')                           3
assert user[0] == 1                                                4
assert user[1] == 'Alex'                                           5
user[1] = 'Bob'                                                    6
assert user.name == 'Bob'                                          7

1.User类定义了getAt的自定义实现
2.User类定义了putAt的自定义实现
3.创建一个user实例
4.使用下标0则会取回用户的id
5.使用下标1则会取回用户的name
6.通过putAt的代理,我们可以通过下标来写属性
7.确定name是否真的被改变了

成员操作符
成员操作符in相当于调用了inCase方法,在List上下文中相当于调用了contains方法,例如下面的例子:

def list = ['Grace','Rob','Emmy']
assert ('Emmy' in list)                   1

1.相当于调用了list.contains('Emmy')list.isCase('Emmy')

恒等操作符
在Groovy中,使用==和在java中使用是不一样的,在Groovy中是相当于调用equals,如果你要比较对象的引用,那么你要调用is

def list1 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']        1
def list2 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']        2
assert list1 == list2                                       3
assert !list1.is(list2)                                     4

1.创建一个元素是String的list
2.创建一个跟list1相同的list
3.使用==来比较两个list
4.但是使用is,我们会发现两个对象是不一样的

强转操作符
强转操作符as是转换的一种变型,强转操作符转换一个对象使其不需要在赋值的时候强制转换,例如:

Integer x = 123
String s = (String) x                                   1

1.Integer不会被强转成String,所以在运行时会报ClassCastException

这个可以使用强转操作符来解决:

Integer x = 123
String s = x as String                                  1

1.Integer不会被强转成String,但是用as则可以

当一个对象强制转化为另一种类型,除非转化的类型是相同的,不然会创建一个新的对象,强转的规则不同取决于转化的类型的不同,如果常规的规则没有找到则会强转失败,自定义转换规则可以实现asType方法:

class Identifiable {
    String name
}
class User {
    Long id
    String name
    def asType(Class target) {                                              1
        if (target == Identifiable) {
            return new Identifiable(name: name)
        }
        throw new ClassCastException("User cannot be coerced into $target")
    }
}
def u = new User(name: 'Xavier')                                           2       
def p = u as Identifiable                                                  3 
assert p instanceof Identifiable                                           4
assert !(p instanceof User)                                                5

1.User定义了一个自定义转换规则来将User转换为Identifiable
2.创建一个User实例
3.使用强转操作符将User转换为Identifiable
4.目标是一个Identifiable实例
5.目标已经不是User实例了

菱形操作符
菱形操作符是一个语法糖,是为了兼容java 7中的菱形操作符。他被用于在声明期间声明泛型:

List strings = new LinkedList<>()

在动态Groovy中,这完全没有用,在Groovy的静态检查中,这也是可选的

调用操作符
调用操作符()是调用了call方法,对于任何定义了call方法的类,你可以省略.call部分而使用调用操作符:

class MyCallable {
    int call(int x) {           1
        2*x
    }
}

def mc = new MyCallable()
assert mc.call(2) == 4          2
assert mc(2) == 4               3

1.MyCallable定义了一个方法名字call,注意他不需要实现java.util.concurrent.Callable
2.我们能通过传统的call方法来调用方法
3.由于call操作符我们可以省略掉.call

操作符优先级
下表按照操作符的优先级列出了groovy中所有的运算符:

Groovy(七)-其他运算符_第1张图片
优先级表
Groovy(七)-其他运算符_第2张图片
优先级表

运算符重载
Groovy允许你重载不同的操作符而使他们可以在你的程序里面使用,例如:

class Bucket {
    int size

    Bucket(int size) { this.size = size }

    Bucket plus(Bucket other) {                     1
        return new Bucket(this.size + other.size)
    }
}

1.Bucket实现了一个特殊的操作符plus()

因为通过重载了plus(),所以Bucket可以使用+在使用中:

def b1 = new Bucket(4)
def b2 = new Bucket(11)
assert (b1 + b2).size == 15                         1

1.两个Bucket可以被+操作符相加在一起

所有的操作符都有一个对应的方法,你可以在自己的程序中实现。唯一要注意的是方法必须为public,名字是对的,参数是一致的。参数的类型取决于你想要支持什么类型的参数在操作符的右边,例如:

assert (b1 + 11).size == 15

通过如下实现plus()

Bucket plus(int capacity) {
    return new Bucket(this.size + capacity)
}

如下表就是操作符以及与之对应的方法:


Groovy(七)-其他运算符_第3张图片

你可能感兴趣的:(Groovy(七)-其他运算符)