繁体   English   中英

首选可变或不可变 collections 作为方法参数

[英]Preferring mutable or immutable collections as method parameters

我正在编写一个将在多个地方使用的库方法。 该方法的参数之一是对象的集合,并且该方法不会改变该集合。 方法签名应该指定一个可变的还是不可变的集合?

选项 1:可变集合作为参数

public static void foo(List<Bar> list) {
  // ...
}

优点:客户端可以传入List<Bar>ImmutableList<Bar>中的任何一个对他们来说更方便。

缺点: list参数不会发生突变并不是很明显。 客户必须阅读文档和/或代码来实现这一点。 无论如何,客户可能会制作不必要的防御性副本。

选项 2:不可变集合作为参数

public static void foo(ImmutableList<Bar> list) {
  // ...
}

优点:客户可以保证list参数不会发生变化。

缺点:如果客户端有List<Bar> ,他们必须在调用foo之前先将其转换为ImmutableList<Bar> 这种转换浪费了少量时间,并且无论他们喜欢与否,它都是强加给客户的。


注意:出于这个问题的目的,我们假设所有客户端都可以使用 Guava 的ImmutableList ,例如因为库和客户端代码都属于已经在其他地方使用ImmutableList的相同代码库。

作为foo() API 的创建者,这不关你的事。 你拿一个清单,你不修改它,就是这样。 实际上,您的代码并不关心列表的可变性(这是调用者关心的问题):因此请记录您的意图并停在那里。

如果调用者需要保证列表不会被篡改,他们会创建防御性副本,这不是因为您没有 promise 保持列表不变,而是因为他们需要那个保证。

它遵循我们在方法实现中执行 null 检查的相同逻辑:需要它是因为我们的代码需要健壮,而不是因为调用者可以发送 null 参数。

换句话说,按照您打算实现它们的方式记录您的方法,并将其留给调用者来选择列表实现。 他们选择的原因会有所不同(即,并不总是只有您是否会修改列表)。

将其留在List

以下是一些需要考虑的情况:

  • Collections.synchronizedCollection不会修改客户端的集合。
    • 如果它强制客户端输入不可变集合,那么将其设为同步集合是没有用的,因为不可变集合已经是线程安全的。
  • Collections.frequency不会修改客户端的集合。
    • 为了检查频率,用户将被迫忍受将元素转移到新集合的额外开销。

这些原因并不是 JDK 不公开不可变接口的原因。 这些原因在文档中进行了解释。 synchronizedCollection的情况下,虽然它不修改客户端的集合,但它确实返回了客户端集合的可修改视图; 有人会说这个 function 在这里不适用。 但是, frequency和其他查询功能仍然很强大。

您不应该为了宣传安全而限制客户,仅此而已。 应该有更多的理由,否则您的帮助可能会成为客户的负担。 在某些情况下,您的目标可能与功能/系统正在实现的目标相矛盾,例如synchronizedCollection示例。

鼓励安全是件好事,但是让您的系统将其强加给您的客户,而系统却没有从中受益,那就是滥用权力; 这不是你的决定。


ernest_k在他的回答中提出了一个非常好的观点,建议您需要分析您的系统应该负责什么,以及客户应该负责什么。 在这种情况下,集合是否不可变应该由客户端决定,因为您的系统不关心可变性。 正如他所说,“这不关你的事”,我同意。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM