天天看点

Java 不可变类的整洁之道

<b>本文讲的是Java 不可变类的整洁之道,</b>

<b></b>

当一个普通类 (class) 的实例不能被修改时,我们便称之为「不可变类」(immutable class)。这样的类在实例化时便需要提供其所有的值,而在之后的运行中便绝不可更改。比如大家可能都知道的 Java 中已有的一些不可变类型,String (string 的字符串联很没效率,对吧), BigInteger, 和 BigDecimal_。

设计一个不可变类有如下的好处:

更简明的设计、实现、和使用

更不容易出错

更安全,因此可以轻松分享

线程安全,无需同步锁

本篇短文希望能够帮助你通过各种不同的方法在 Java 中更简洁地创建和生成不可变类。我们会谈到两种最常见代码生成库:Immutables 和 AutoValue,以及 Guava’s 中的一些不可变集合 (collection)。

我个人认为这两种库各有千秋,所以本文并不会去比较这两者。你应当根据自己的代码库和实际需求来决定选择更适合你的那一个。

将一个类变为「不可变」类有以下几项基本步骤:

不可继承 为类添加 final 修饰即可,这样可预防恶意代码通过继承来改变该类的任何状态。

所有类变量都不可更改. 将变量全都设置为 final 时,所有的值都需要通过在构造函数中便传入,或者另建立一个生成器模式 (builder pattern)。

将所有类变量都设置为私有 (private). 显然,如果仍然设置为公共 (public),这些类变量的值都有可能被读取和修改。

在 Java 中使用不可变类:

所有类值都是 private 和 final,类本身也是 final,且没有任何可变函数。

当需要一个能返回某类实例的函数时,则一定要返回一个全新的实例。假设此处的 Autobot 类有一个 fusion(Autobot) 函数,且传入给它另一个 Autobot 的话,它便会融合这两个 Autobot。

本文将会提供一些能够帮助你节省时间的不可变类结构自动生成工具。之所以需要代码自动生成,是因为它省时,且通过了周全的测试,其中也没有难懂的部分,只是在建构时便自动生成,何乐而不为呢。

以上代码示范了如何在单纯 Java 环境下建造一个不可变类。虽然需要真正去写的代码并不多,但当代码中有许多类变量或代码本身采用的是生成器模式时,模版代码 (boilerplate code) 的书写量便会大增,而这不正好是代码生成工具擅长的!

以上这个 Deception 类将会生成 280 行的不可变拓展类,且提供一些非常实用的函数,例如copyOf(Deception),toString(),hashCode(),_equals(),以及一个好用且流畅的生成器 (builder)。

不仅如此,不可变型还可以声明为接口。

这样便可以在接口之间实现多个拓展,以达到仿多重继承的效果:

还有其他一些有趣实用的特点,例如如果我们不想用生成器模式时,只要通过 Immutables 注解那些类变量来标记构造函数即可。

更重要的是! Immutables 甚至支持 Guava’s 的 Optional 类型!

AutoValue 是由 Google 的员工所创建,且是 Auto 计划的一部分。它包括了许多 Java 自动生成的源代码,例如AutoFactory, AutoService 和其他一些常用的代码生成工具。

简而言之,你可以只写抽象类,让 AutoValue 帮你实现它。

之前同样的例子便可以修改为:

编译后,AutoValue 就会自动生成一个 AutoValue_Autobot 类。

虽然效果很好,但也应该避免在自己的代码中显示 AutoValue 这样的第三方代码库。以下方法可以让代码更简明易懂,且隐藏 API。

这样的话,创建 Autobot 时便能更好的隐藏 API。

如同 Immutables 库,当我们查看生成后的类时会发现,它也同样自动生成了 equals(), toString() 和 hashCode() 函数,甚至还有参数验证。

同样,你也可以生成 builder,虽然如果採用 Immuables 可能会需要写一点额外的代码,不过你可以对比一下两者的优点来决定採用哪一个。

我个人认为生成器模式会让代码更干净易读:

也可以提供许多不可变类的帮助,不同之处在于 Guava 不会为你生成代码,它只是提供一些不可变的集合:

ImmutableList

ImmutableSet

ImmutableSortedSet

ImmutableMap

ImmutableSortedMap

ImmutableMultiset

ImmutableSortedMultiset

ImmutableMultimap

ImmutableListMultimap

ImmutableSetMultimap

ImmutableBiMap

ImmutableClassToInstanceMap

ImmutableTable

The usage is based on static classes, iterators and helpers. 以上都是静态的类、迭代器 (iterator)、或工具类(helper)。

<b>原文发布时间为:2016年06月27日</b>

<b>本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。</b>