高效的Kotlin——限制可变性

限制可变性(Limit mutability)

只读属性 val

只读属性val可以改变,但是只读属性并没有提供修改的切入点,而修改切入点才是引起同步或者其他问题的主要原因。
尽管val并不意味着“不可变”,例如我们可以通过自定义getter或者属性代理的方式定义val属性,这的确给了我们更多改变属性值的自由,但是在没有这些需求时,我们应该更倾向于使用final properties,Kotlin对其有更好的支持,例如smart cast:

val name: String? = "Márton"
val surname: String = "Braun"
val fullName: String?
    get() = name?.let { "$it $surname" }
val fullName2: String? = name?.let { "$it $surname" }
fun main() {
    if (fullName != null) {
        println(fullName.length) // ERROR: Smart cast impossible
    }
    if (fullName2 != null) {
        println(fullName2.length) // Márton Braun
    }
}

区分只读、可变集合

Kotlin支持只读集合(read-only collections),Kotlin的只读集合是通过集合类的继承层次结构上的“有意”设计而达成的,具体说来就是,把集合类分为可变集合类和只读集合类,所有的可变集合类都继承自相应的只读集合类。

只读集合也不一定是不可变的,并且在底层实现上它们往往还真的就是可变集合,只是这些具体的实现被封装在只读接口之下,所以我们不能“轻易地”修改只读集合。例如,Iterable<T>.map, Iterable<T>.filter就是返回的ArrayList,但是通过只读接口List进行了屏蔽:

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    val destination = ArrayList<R>(collectionSizeOrDefault(10)); transform)
    for (item in this)
        destination.add(transform(item))
    return destination
}

把只读集合设计成只读的而不是不可变的,给了我们更多的灵活性。在底层实现上,只要求具体的实现满足只读集合的接口即可,这样可以使用平台特定(platform-specific)的集合来实现Kotlin的只读集合(别忘了,Kotlin可是跨平台的语言)。
但是,希望Kotlin提供真正的不可变集合的呼声一直是络绎不绝,Kotlin也听到了大家的呼声,在kotlinx中提供了相应实现,具体参见kotlinx.collections.immutable,其中提供了不可变集合(Immutable collections)和持久化集合(Persistent collections)。

总结

我们应该限制可变性并且尽可能使用“不可变”对象,Kotlin提供了很多相关的工具,我们应该善于使用它们来限制修改切入点(mutation points):

  1. 更多地使用val而不是var
  2. 更多地使用不可变属性。
  3. 更多地使用不可变类/对象(data class)。
  4. 如果需要修改一个对象的属性,考虑使用data class并且使用copy
  5. 当需要持有某种状态时,更多地使用只读集合而不是可变集合。
  6. 审慎地提供修改切入点,不要提供不必要的修改切入点。
  7. 不要对外暴露可变对象(mutable objects)。

以上规则当然会有例外,例如,我们可能会想使用可变对象来提高效率,当性能成为瓶颈的时候,的确可以考虑这么做,但是你应该知道,可变性意味着在多线程时需要格外的小心。使用可变对象从状态修改的角度看的确可以提升效率,但是如果叠加由此引发的多线程锁的开销,可变对象是否真的能提升效率就是一件值得考虑的事情了。总之,我们应该限制可变性。


从Immutability这一点其实可以看出编程语言的演进和软件工程的进化。Kotlin是“现代语言”中,选择拥抱Immutability的。

从设计上看,可变和不可变属性是平等的(varval等长且很相似),甚至对于集合而言还更偏向于不可变集合(List vs MutableList),这些都是有意为之。相较而言,Java的可变和不可变就不是平等的(final vs 没有final),你或许会说Java更好啊,多个关键字更加的明确,但是扪心自问,是不是因为多个关键字你反而用的少得多。这不仅仅是个关键字的差别,表象背后体现的是编程哲学的不同。
更多内容可以查看这篇文章Immutability we can afford,作者Kotlin Leader。

Immutability is a luxury of programming, making software more comfortable and less error-prone to write in many important cases. Immutability is becoming more popular in software development because we became so rich in machine resources that we can afford it now.

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

推荐阅读更多精彩内容