Groovy学习笔记4:特殊注解

1.@Canonical

如果要编写的toString()方法只是简单地显示以逗号分隔的字段值,则可以使用@Canonical变换让Grooovy编译器帮来干这个活。

默认情况下,它生成的代码会包含所有字段。不过可以让它仅包含特定字段,而去掉其他字段。

@Canonical
class Student {
    String firstName
    String lastName
    int age
    String address
}

def student = new Student(firstName: "Zhang",
        lastName: "Sanfeng",
        age: 16,
        address: "China")

println student

输出:

Student(Zhang, Sanfeng, 16, China)

不管如何,这个注解在打印Log等情况下,可堪一用。

2.@Delegate

只有当派生类是真正可替换的,而且可代替基类使用时,继承才显示出其优势。从纯粹的代码复用角度看,对于其他大部分用途,委托要优于继承

然而在Java中我们不太愿意使用委托,因为会导致代码冗余,而且需要更多工作。Groovy使委托变得非常容易,所以我们可以做出正确的设计选择。

class Worker {
    def work() { println 'get work done' }

    def analyze() { println 'analysis...'}

    def writeReport() { println 'get report written' }
}

class Expert {

    def analyze() { println 'expert analysis...' }
}

class Manager {

    @Delegate
    Expert expert = new Expert()
    @Delegate
    Worker worker = new Worker()
}

def manager = new Manager()
manager.analyze()
manager.work()
manager.writeReport()

在编译时,Groovy会检查Manager类,如果该类中没有被委托类中的方法,就把这些方法从被委托类中引入进来。因此,首先它会引入Expert类中的analyze()方法。

而从Worker类中,只会把work()和writeReport()方法因为进来。这时候,因为从Expert类带来的analyze()方法已经出现在Manager类中,所以Worker类中的analyze()方法会被忽略。

对于引入的每个方法,Groovy会简单地把对该方法的调用路由给实例上的相应方法,就像这样:publicObjectanalyze(){ expert.analyze() }。委托类会对新获得的方法做出响应,在下面的输出中可以看到:

expert analysis...
get work done
get report written

因为有了@Delegate注解,Manager类是可扩展的。如果在Worker或Expert类上添加或去掉了方法,不必对Manager类做任何修改,相应的变化就会生效。只需要重新编译代码,剩下的事Groovy会处理。

3.@Immutable

不可变对象天生是线程安全的,将其字段标记为final是很好的实践选择。如果用@Immutable注解标记一个类,Groovy会将其字段标记为final的,并且额外为我们创建一些便捷方法,从而使得“做正确的事情”变得更容易了。

@Immutable
class ImmutableStudent {

    String name
    int age
}
println new ImmutableStudent("jack", 24)

作为反馈,Groovy给我们提供了一个构造器,其参数以类中字段定义的顺序依次列出。在构造时间过后,字段就无法修改了。此外,Groovy还添加了hashCode()、equals()和toString()方法。

运行所提供的构造器和toString()方法:

ImmutableStudent(jack, 24)

可以使用@Immutable注解轻松地创建轻量级的不可变值对象。在基于Actor模型的并发应用中,线程安全是个大问题,而这些不可变值对象是作为消息传递的理想实例。

4.@Lazy

我们想把耗时对象的构建推迟到真正需要时。完全可以懒惰与高效并得,编写更少的代码,同时又能获得惰性初始化的所有好处。

下面的例子将推迟创建Heavy实例,直到真正需要它时。既可以在声明的地方直接初始化实例,也可以将创建逻辑包在一个闭包中。

class Heavy {
    def size = 10

    Heavy() { println "Creating Heavy : Size = $size"  }
}

class AsNeed {
    def value

    @Lazy  Heavy heavy1 = new Heavy()
    @Lazy  Heavy heavy2 = {  new Heavy(size: value)  }()

    AsNeed() { println 'Created AsNeed' }
}

def need = new AsNeed(value: 1000)
println need.heavy1.size
println need.heavy1.size
println need.heavy2.size

Groovy不仅推迟了创建,还将字段标记为volatile,并确保创建期间是线程安全的。实例会在第一次访问这些字段的时候被创建,在输出中可以看到:

Created AsNeed
Creating Heavy : Size = 10
10
10
Creating Heavy : Size = 10
1000

另一个好处是,@Lazy注解提供了一种轻松实现线程安全虚拟代理模式(virtual proxy pattern)的方式。

5.@Newify

在Groovy中,经常会按照传统的Java语法,使用new来创建实例。然而,在创建DSL时,去掉这个关键字,表达会更流畅。

@Newify注解可以帮助创建类似Ruby的构造器,在这里,new是该类的一个方法。该注解还可以用来创建类似Python的构造器(也类似Scala的applicator),这里可以完全去掉new。要创建类似Python的构造器,必须向@Newify注解指明类型列表。

只有将auto=false这个值作为一个参数设置给@Newify,Groovy才会创建Ruby风格的构造器。可以在不同的作用域中使用@Newify注解,比如类或方法,如下面例子所示:

@Newify(value = [Student, ImmutableStudent])
def fluentCreate() {

    println Student.new(firstName: "Zhang", lastName: "Sanfeng", 
                        age: 24, address: "China")
    println ImmutableStudent.new("LiHua", 29)
}

fluentCreate()

结果:

Student(Zhang, Sanfeng, 24, China)
ImmutableStudent(LiHua, 29)

在创建DSL时,@Newify注解非常有用,它可以使得实例创建更像是一个隐式操作。

6.@Singleton

要实现单件模式,正常来讲,我们会创建一个静态字段,并创建一个静态方法来初始化该字段,然后返回单件实例。我们必须确保该方法是线程安全的,同时还要决定是否要惰性创建该单件。

而通过使用@Singleton变换则完全可以避免这种麻烦,如下面例子所示:

@Singleton(lazy = true, strict = false)
class President {

    private President() {
        println 'Instance'
    }

    def hello() {
        println 'hello'
    }
}

President.instance.hello()
President.instance.hello()

输出:

Instance
hello
hello

这里使用@Singleton注解标记了TheUnique类,以生成静态的getInstance()方法。因为此处将lazy属性的值设为了true,所以会将实例的创建延迟到请求时。

Groovy不仅将实例创建延迟到了最后责任时刻,还保证创建部分是线程安全的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,652评论 18 139
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,201评论 9 118
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,806评论 6 342
  • Groovy学习目录-传送门 元编程(Metaprogramming)->百度百科 Groovy语言支持两种类型的...
    化作春泥_阅读 9,054评论 0 19
  • 所谓洞见依托的是一整套关于未来的想法。当一个人系统性地思考了未来是什么样子,社会生活如何运转,那么才有可能提出在某...
    Becky1801阅读 353评论 0 1