BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

拥抱可变性

| 作者 Enrique López Mañas 关注 0 他的粉丝 ,译者 薛命灯 关注 24 他的粉丝 发布于 2017年3月8日. 估计阅读时间: 6 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

我是一个老Java人,从来没有对可变性问题有过太多的想法。Java不像其它语言,它没有确切的机制可以用于控制可变性和不可变性。我从来没有听说过Java对象有这样的特性。相反,我总是听到有人这么说它:“那个Java类没有setter方法”或者“那个Java类的值初始化之后就不能被修改”。这些都是对Java不可变性非正式的描述。可变性是命令式语言的默认行为,但我们从来没有仔细想过这一点。我们学习了这种编程范式,它们就进入到了我们的潜意识里。

在我的整个职业生涯中,我见过很多编程语言,它们对类的可变性区分得非常清楚。这个看起来很酷,不过我很少会用到它们(我的大部分工作是关于Android和J2EE),所以就这么过去了。它们不在我的影响力范围之内。

一年前,我开始使用Kotlin。它给我的开发工作注入了一股清流,如果有可能,我会尽量使用它来开发(我参与了Kotlin Weekly,如果有兴趣可以订阅它)。如果让你来做Android开发,你可能会选择Java。Java 1.0版本发布于1995年,也就是22年前。那时候的世界是另外一番景象,Java被设计用于解决当时存在的一些问题。那个时候还没有智能手机,普通手机也不像今天这样有这么多功能。在Java发布的时候,Windows 95都还没有公开发布(它跟Java一样老),eBay才刚刚成立。

我喜欢拿IT行业同股票市场作类比。在60年代,通用汽车是当时的巨无霸,没有哪个公司能够与之竞争。美国政府甚至想过要强行将通用公司拆分成几个小公司,避免它的垄断。而在今天,通用汽车犹如行尸走肉,在一次大型的救市之后幸存下来。在90年代,没有人想到Apple会在今天成为最大的全球化公司。

今日之星或将于明日陨落,而今日之停船或将于明日启航。

—— J.L. Collins《财富之路》

Java经历了很多的更新。我不只是在谈论Java,实际上我以Java为生,尽管并不仅限于Java。不过还有众多新星在升起,比如Kotlin。Kotlin提供了开箱即用的可变集合和不可变的集合。

最近,我的同事Mike Nakhimovich在Twitter上写道:

“把所有的东西都变成不可变的来避免可变性?”

这句话引起了我的思考。最近我发表了一篇博文“合理使用volatile和synchronized”,我意识到多线程和同步问题真的很复杂。它们有太多的边界情况,太多的概念,太多的抽象。而这个居然是开箱即用的解决方案。我偶尔会用到它们,不过我觉得它们更像是骇客行为。

现在让我们进入Java的可变性世界。为了简单起见,我们先对不可变性进行定义:

不可变类被创建之后,其状态就不能被更改。

这看起来很简单。如果你也是个Java开发者,或许现在就知道该怎样创建一个不可变的类:

  • 所有的属性必须是private的。这个也是面向对象编程的另一个规则。如果一个属性是private的,那么就不能直接在外部对其进行修改。最好还是final的,这样就完全不能进行修改了。
  • 不要提供setter方法。这一点可以与第一点结合起来使用。如果属性是private的,并且没有提供setter方法,那么这个类的状态就不会发生变化。
  • 子类不能覆盖父类的方法。否则的话,就不能保证不可变性。要做到这一点很简单,只要把类声明为final的。

我们已经讲解了理论部分,接下来我们可以做点什么呢?

好的方面

  • 不可变对象会让事情变得更简单。不可变对象是线程安全的,不存在同步问题。这是一个很大的优势!它们让并发编程更安全更简单。如果你调试过并发代码,就会知道大部分缺陷是因为在多个线程间使用了共享状态引起的。通过使用不可变对象可以在一瞬间解决这些问题,所以值得一试。
  • 不可变对象不需要拷贝构造函数,也不需要实现clone方法。这样代码就简单了很多。
  • Joshua Bloch在《Effective Java》里提到过故障原子性的概念,当不可变对象跑出异常时,它不会让对象处于一个不确定的状态。

不好的方面

  • 需要通过拷贝对象才能对其进行修改,这样会占用额外的资源,特别是对于那些复杂的数据结构来说。另外,通过唯一标识来管理和更改对象不是一种很直观的方法。
  • 我们所能感知到的模型对象是可变的。

我该作何选择?

有人说“可变性是万恶之源”。我喜欢有更多的选择,不想让任何事物成为教条。Joshua Bloch在《Effective Java》里写道:

“类应该是不可变的,除非有充分的理由让它变为可变的。如果一个类不能被定义为不可变的,那么也要尽可能限制它的可变性。”

不可变性能够解决很多问题,也会让事情变简单,特别是在并发环境里。不过如果把不可变作为默认行为,反而会带来复杂性。所以,在决定使用可变性还是不可变性时,要根据实际情况选择最合适的方案。

本文已获得原作者翻译授权,查看原文:Learning to use and abuse Mutability

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

Effective Java 3rd Edith by 刘 波

Effective Java 3rd Edith 中文版 快上市了吗

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

1 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT