ImmutableList vs List-我应该将其转换为什么?

ImmutableList vs List- what should I cast it as?

我知道将所有 List 实施转换为 List 是普遍接受的做法。无论是变量、方法return,还是使用ArrayListCopyOnWriteArrayList等的方法参数

List<Market> mkts = new ArrayList<>();

当我使用 Guava ImmutableList 时,我感觉它可以说是这条规则的一个例外(特别是如果我正在构建内部复杂的业务应用程序而不是 public API)。因为如果我把它放到列表中,已弃用的增变器方法将不再被标记为已弃用。此外,它不再被标识为不可变对象,这是其功能和身份的一个非常重要的部分。

List<Market> mkts = ImmutableList.of(mkt1,mkt2,mkt3);

因此将它作为 ImmutableList 传递是有意义的,对吗?我什至可以争辩说,内部 API 只接受 ImmutableList 是一个很好的策略,因此客户端的可变性和多线程不会破坏库中的任何东西。

ImmutableList<Market> mkts = ImmutableList.of(mkt1,mkt2,mkt3);

我知道 ImmutableList 本身存在被弃用的风险,Oracle 决定创建自己的 ImmutableList 的那一天将需要大量重构。但是否可以说维持 ImmutableList 演员阵容的利大于弊?

不幸的是,Java 中没有相应的界面(很可能永远不会)。所以我的做法是假装 ImmutableList 是一个接口。 :D 但说真的,它添加了不应丢失的重要信息。

这一切都来自古老的规则,实际上是这样说的 "program against interfaces"。 IIRC 在创建规则时,周围没有 Java,"interface" 表示编程接口,即合同,而不是 java interface

类似

的方法
void strange(ArrayList list) {...}

显然很奇怪,因为没有理由不使用 List。包含 ImmutableList 的签名有充分的理由。


I know there is a risk of ImmutableList itself becoming deprecated, and the day Oracle decides to create its own ImmutableList will require a lot of refactoring.

你是说Java 18?让我们看看,但是 Guava 的 ImmutableList 非常好,设计这样一个 class 不同的意义不大。因此,您可以希望大多数更改仅发生在您的导入中。到 2050 年,还会有比这更严重的问题。

我理解你的困境。

Personnaly,我会建议继续使用 List 作为引用类型(面向未来并从多态性中受益),并使用 @Immutable 注释来传达它是不可变的。

注释比普通的 javadoc 注释更明显,您甚至可以使用 JSR-305(ex-JCIP)中的注释。 一些静态分析工具甚至可以检测到它并验证您的对象没有发生变异。

我宁愿只使用 List 作为方法参数。强制调用者传递 ImmutableList 没有多大好处 - 这是你自己的方法,无论如何你都不会改变列表,但你会有更可重用和通用的方法。

作为 return 类型,我会选择 ImmutableList 让方法用户知道无法修改此列表。

我同意你的理由。如果您使用的是 Guava 集合库并且您的列表是不可变的,那么将它们作为 ImmutableList 传递是个好主意。

但是:

I know there is a risk of ImmutableList itself becoming deprecated, and the day Oracle decides to create its own ImmutableList will require a lot of refactoring.

第一种情况似乎不太可能,但无论何时使用 any 第 3 方库,这都是一种风险。但不利的一面是,如果应用程序的 Guava 版本 (Google) 无故弃用了您所依赖的 class 或方法,您可以选择不升级它们。

更新

Louis Wasserman(为 Google 工作)在评论中说:

"Guava provides pretty strong compatibility guarantees for non-@Beta APIs."

因此我们可以降低无故 API 更改的可能性。


第二种情况更不可能(IMO)。而且您可以确定,如果 Oracle 确实添加了不可变列表 class 或接口,那将不会 要求 您进行重构。 Oracle 在增强标准 APIs.

时非常努力地避免破坏现有代码

但话虽如此,权衡利弊……以及如果最终发生时您将如何处理利弊,真的取决于您。

继续使用 List 而不是 ImmutableList 这没有问题,您的 API 也没有理由开始使用 ImmutableLists 明确地出于几个原因:

  1. ImmutableList 只是 Guava,在任何时候都不太可能成为标准 Java。不要将您的代码和编码习惯绑定到第三方库(即使它是像 Guava 这样很酷的库)。
  2. 在 Java 中使用不可变对象是一种很好的做法,并且在开发 API 时尤为重要(请参阅有效 Java 项目 15 - 最小化可变性)。这是一个可以想当然的通用概念,不需要以接口的名称来传达。同样,您也不会考虑调用为继承 UserThatCanBeSubclassed 而设计的用户 class。
  3. 以稳定性的名义,您的 API 永远不应开始修改传递给它的 List,并且在将 List 传递给客户端时始终制作防御性副本。在这里介绍 ImmutableList 会引诱您和您 API 的客户产生一种虚假的安全感,并诱使他们违反该规则。