日积月累--Groovy语言规范之操作符
这篇文章介绍的是Groovy编程语言的操作符,不知为何Groovy将其单独列为了一个部分。 再次说明一下:本文不是对官方文档的完完整整翻译,而是掺杂了一些个人的理解,使其更加本土化。关于Groovy的一些语法,可参照我的另一篇文章(http://www.voidcn.com/article/p-hglihmaw-uv.html); 1. 算术运算符Arithmetic operators同Java语言一样Groovy支持同样的算术运算符。 1.1. 普通算术运算符Normal arithmetic operators以下这些二元算术运算符在Groovy中是适用的:
举一些例子: 这个没啥难点,主要是关于除以和幂。整数的除以得到的结果和java中有所不同,如若想达到java中的效果,需要使用intdiv()方法,具体参考:我的另一篇文章(http://www.voidcn.com/article/p-hglihmaw-uv.html); 1.2. 一元运算符Unary operators共三个+,-,++,–这个和Java中相同 def a = 2 def b = a++ * 3 assert a == 3 && b == 6 def c = 3 def d = c-- * 2 assert c == 2 && d == 6 def e = 1 def f = ++e + 3 assert e == 2 && f == 5 def g = 4 def h = --g + 1 assert g == 3 && h == 4 1.3. 赋值运算符Assignment arithmetic operators我们上面看到的二元算术运算符同样可以用作赋值运算符:
来看看它们的表现: 2. 关系运算符Relational operators关系运算符允许两个对象间的比较,以确定其二者是否相同,或者用于判断那个大,那个小,还是相等。
举几个它们之间比较的例子: 3.逻辑运算符 Logical operatorsGroovy提供了三个用于布尔表达式的逻辑运算符:
通过几个例子阐述一下: 这里需要说明的是Groovy中的&&、||与Java中的含义相同。 3.1.优先级 Precedence“非”的优先级大于”且” assert (!false && false) == false “且”的优先级高于”或” assert true || true && false 3.2. 短路Short-circuiting这些知识同Java,短路的目的说白了就是效率高一些。 boolean checkIfCalled() { called = true } called = false true || checkIfCalled() assert !called called = false false || checkIfCalled() assert called called = false false && checkIfCalled() assert !called called = false true && checkIfCalled() assert called 4.位运算符 Bitwise operators同Java:
位运算符可以被应用答byte或int类型的运算,且返回值为int类型: It’s worth noting that the internal representation of primitive types follow the Java Language Specification. In particular,primitive types are signed,meaning that for a bitwise negation,it is always good to use a mask to retrieve only the necessary bits. 5. 条件运算符Conditional operators5.1. Not操作符 Not operatorThe “not” operator is represented with an exclamation mark (!) and inverts the result of the underlying boolean expression. In particular,it is possible to combine the not operator with the Groovy truth: assert (!true) == false // true的否定是false assert (!'foo') == false // 'foo'不是一个空字符串,计算结果为true,再否定后返回false assert (!'') == true //参照上一个注释 5.2. 三元运算符Ternary operator三元运算符是一种简洁的写法,其等同于if/else if (string!=null && string.length()>0) { result = 'Found' } else { result = 'Not found' } 你可以使用三元运算符表达式代替: result = (string!=null && string.length()>0) ? 'Found' : 'Not found' 应用Groovy truth中的规则,你还可以更简洁: result = string ? 'Found' : 'Not found' 之所以可以这样写,是因为在Groovy truth的规则中:直接一个字符串为空则为false,不为空则为true。 5.3. Elvis操作符 Elvis operatorThe “Elvis operator” is a shortening of the ternary operator. One instance of where this is handy is for returning a ‘sensible default’ value if an expression resolves to false-ish (as in Groovy truth). A simple example might look like this: displayName = user.name ? user.name : 'Anonymous' displayName = user.name ?: 'Anonymous' 这两个表达式的结果是等同的。而三元表达式显得有些臃肿。 6. 对象操作符 Object operators6.1. Safe navigation operator暂且翻译为:安全引用操作符。 def person = Person.find { it.id == 123 } //返回一个Person对象person为null def name = person?.name //使用这种操作符避免了空指针异常 assert name == null 6.2. 直接访问字段操作符 Direct field access operator我们通常这样写代码,例如: class User { public final String name User(String name) { this.name = name} String getName() { "Name: $name" } } def user = new User('Bob') assert user.name == 'Name: Bob' 对于初学者,说明一下:user.name等价于user.getName()而不是对字段的直接获取。对于Groovy而言,对字段默认生成getter,返回的是该字段的值。 assert user.@name == 'Bob' 6.2 方法指针操作符 Method pointer operator方法指针操作符(.&)被用于储存一个方法的索引到变量中,以便于后续的调用: def str = 'example of method reference' //str变量包含一个字符串 def fun = str.&toUpperCase//将str实例的toUpperCase方法作为索引储存在fun变量中 def upper = fun()//像普通方法一样调用。 assert upper == str.toUpperCase() 使用这种方法指针有诸多的好处。首先,这种类型的方法指针,是一种groovy.lang.Closure(闭包),所以闭包可以使用的任何地方都可以被方法指针代替。特别的,将现存的方法按照需求转化成指针方法也是合适的. def transform(List elements,Closure action) { def result = [] elements.each { result << action(it) } result } String describe(Person p) { "$p.name is $p.age" } def action = this.&describe def list = [ new Person(name: 'Bob',age: 42),new Person(name: 'Julia',age: 35)] assert transform(list,action) == ['Bob is 42','Julia is 35'] ①transform方法里面的集合的遍历(后续会有介绍)。这个遍历调用闭包,返回一个新的集合。 class Person{ public final String name; public final int age; public Person(Map map){ this.name=map.name; this.age=map.age; } } 方法指针包含返回值和方法名。参数会在运行时进行解析,也就意味着,如果多个方法的方法名相同,语法结构不同,在运行时只有恰当的方法会被调用(和java中的就近元素相似): def doSomething(String str) { str.toUpperCase() } def doSomething(Integer x) { 2*x } def reference = this.&doSomething assert reference('foo') == 'FOO' assert reference(123) == 246 7. 正则表达式操作符 Regular expression operators7.1 模式操作符Pattern operator模式操作符(~)提供了一个简单的方式来创建java.util.regex.Pattern实例: def p = ~/foo/ assert p instanceof Pattern 通常你会发现模式操作符是一个正斜杠字符串表达式,因为在Groovy中它可以是任意类型的字符串。 p = ~'foo' //使用单引号字符串 p = ~"foo" //使用双引号字符串 p = ~$/dollar/slashy $ string/$ //使用美元-正斜杠字符串 p = ~"${pattern}" //可以使用GString 7.2.查找字符串 Find operator##你可以直接使用查找操作符(=~)来创建一个java.util.regex.Matcher实例: def text = "some text to match" def m = text =~ /match/ assert m instanceof Matcher if (!m) { throw new RuntimeException("Oops,text not found!") }
Since a Matcher coerces to a boolean by calling its find method,the =~ operator is consistent with the simple use of Perl’s =~ operator,when it appears as a predicate (in if,while,etc.). 7.3 匹配操作符 Match operator匹配操作符(==~)是查找操作符的一个变形,返回的是boolean而不是Matcher,对输入的字符串要求严格的匹配: m = text ==~ /match/ //==~使用正则表达式匹配这个subject,但是匹配规则是严格的 assert m instanceof Boolean //返回值是一个boolean值 if (m) { //等同于调用if (text ==~ /match/) throw new RuntimeException("Should not reach that point!") } 8. 其他操作符 Other operators8.1 展开操作符 Spread operator展开操作符(*.)通常被集合对象调用其所有的对象使用。等价于遍历调用,并将结果收集在一个集合中: class Car { String make String model } def cars = [ new Car(make: 'Peugeot',model: '508'),new Car(make: 'Renault',model: 'Clio')] def makes = cars*.make //返回一个只包含make条目的集合 assert makes == ['Peugeot','Renault'] 展开操作符是一个指针安全操作符,即即使返回值是一个空指针也不会抛出NullPointerException而代之返回null cars = [ new Car(make: 'Peugeot',null,model: 'Clio')] assert cars*.make == ['Peugeot','Renault'] assert null*.make == null 展开操作符可以被用在任意一个实现了Iterable接口的类中: class Component { Long id String name } class CompositeObject implements Iterable<Component> { def components = [ new Component(id: 1,name: 'Foo'),new Component(id: 2,name: 'Bar')] @Override Iterator<Component> iterator() { components.iterator() } } def composite = new CompositeObject() assert composite*.id == [1,2] assert composite*.name == ['Foo','Bar'] 8.1.1.展开方法参数 Spreading method arguments有这样一种情况,即方法中的参数个数如果等同于一个集合,在这种情况下,你可以使用展开操作符作为参数被这个方法调用。例如: 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,6) == 26 8.1.2. 展开集合元素Spread list elements不再赘述,直接上代码: def items = [4,5] def list = [1,2,3,*items,6] assert list == [1,4,6] 8.1.3.展开map集合 Spread map elements不再赘述,直接上代码,需要注意的是不同于集合,这里使用的是(*:) def m1 = [c:3,d:4] def map = [a:1,b:2,*:m1] assert map == [a:1,c:3,d:4] 8.2 区间操作符 Range operatorGroovy支持区间的概念,提供了符号(..)来生成区间对象: def range = 0..5 assert (0..5).collect() == [0,1,5] assert (0..<5).collect() == [0,4] assert (0..5) instanceof List //groovy.lang.Range实现了List接口 assert (0..5).size() == 6 你可以创建任意的Comparable对象并具有next()和previous()方法。例如: assert ('a'..'d').collect() == ['a','b','c','d'] 8.3 比较操作符 Spaceship operator比较操作符(<=>)代表了compareTo方法: assert (1 <=> 1) == 0 assert (1 <=> 2) == -1 assert (2 <=> 1) == 1 assert ('a' <=> 'z') == -1 8.4.下标操作符 Subscript operator不好解释,直接上代码:可用于替代方面:getAt()和putAt(); def list = [0,4] assert list[2] == 2 //可以被getAt(2)代替使用 list[2] = 4 //putAt assert list[0..2] == [0,4] list[0..2] = [6,6,6] assert list == [6,4] 下标操作符,是一个简便的方式代替自定义的getAt/putAt class User { Long id String name def getAt(int i) { switch (i) { case 0: return id case 1: return name } throw new IllegalArgumentException("No such element $i") } void putAt(int i,def value) { 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') assert user[0] == 1 assert user[1] == 'Alex' user[1] = 'Bob' assert user.name == 'Bob' 8.5.in操作符 Membership operatorin操作符等价于isCase方法。在一个集合中,它等价于调用contains,例如: def list = ['Grace','Rob','Emmy'] assert ('Emmy' in list) 等价于调用:list.contains(‘Emmy’)或者list.isCase(‘Emmy’) 8.6. 身份识别操作符Identity operator在Groovy中,使用(==)等同于Java中的这个操作符。在Groovy中,也可以调用equals。如果你想要比较两个索引,你应该使用is比如下面的例子: 8.7.强制操作符 Coercion operator强制操作符(as)用于变量的强制转换。强制转换操作符转换对象从一个类型向另外一个类型而不考虑其兼容性。举个例子: Integer x = 123 String s = (String) x 由于Integer不可以自动转化成String,所以在运行时会抛出一个ClassCastException 。 Integer x = 123 String s = x as String 在强转一个对象到另一种类型是,除非目标类型是同一种源码类型,强转才会返回一个新的对象。自定义的强转规则如果实现了asType方法,也可以强转: class Identifiable { String name } class User { Long id String name def asType(Class target) { if (target==Identifiable) { return new Identifiable(name: name) } throw new ClassCastException("User cannot be coerced into $target") } } def u = new User(name: 'Xavier') def p = u as Identifiable assert p instanceof Identifiable assert !(p instanceof User) 8.8.钻石运算符 Diamond operator钻石运算符在java中也有出现在java7中,具有自动推断的能力。 List strings = new LinkedList 8.9. 调用操作符Call operator调用操作符()被用来默认调用名为call的方法。定义了call方法的对象,你可以使用调用操作符来取代.call class MyCallable { int call(int x) { 2*x } } def mc = new MyCallable() assert mc.call(2) == 4 assert mc(2) == 4 9. 操作符优先级Operator precedence下标按优先级列出了Groovy所有的操作符
10. Operator overloadingGroovy允许重载各种操作符所以你可以将这些应用于你自己的类。考虑以这个简单的类: class Bucket { int size Bucket(int size) { this.size = size } Bucket plus(Bucket other) { return new Bucket(this.size + other.size) } } 注意:Bucket实现了特殊的方法被称作plus(); def b1 = new Bucket(4) def b2 = new Bucket(11) assert (b1 + b2).size == 15 所有(不含比较器)的Groovy操作符都有相应的方法你可以在你自己的类中予以实现。仅仅要求你的这些方法是public,名称正确,参数数量正确。参数类型,取决于你想要支持的类型。例如,你可以支持以下声明: assert (b1+11).size == 15 通过实现plus()方法: Bucket plus(int capacity) { return new Bucket(this.size + capacity) } 下面是一个操作符于相应方法的表格:
Groovy的操作符告一段路……..2016-1-11 14:05; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |