简体   繁体   English

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

[英]Preferring mutable or immutable collections as method parameters

I'm writing a library method that will be used in several places.我正在编写一个将在多个地方使用的库方法。 One of the method's parameters is a collection of objects, and the method does not mutate this collection.该方法的参数之一是对象的集合,并且该方法不会改变该集合。 Should the method signature specify a mutable or immutable collection?方法签名应该指定一个可变的还是不可变的集合?

Option 1: mutable collection as parameter选项 1:可变集合作为参数

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

Pros: Clients can pass in whichever of List<Bar> or ImmutableList<Bar> is more convenient for them.优点:客户端可以传入List<Bar>ImmutableList<Bar>中的任何一个对他们来说更方便。

Cons: It is not immediately obvious that the list parameter will not be mutated.缺点: list参数不会发生突变并不是很明显。 Clients must read documentation and/or code to realize this.客户必须阅读文档和/或代码来实现这一点。 Clients may make unnecessary defensive copies anyway.无论如何,客户可能会制作不必要的防御性副本。

Option 2: immutable collection as parameter选项 2:不可变集合作为参数

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

Pros: Clients have a guarantee that the list parameter will not be mutated.优点:客户可以保证list参数不会发生变化。

Cons: If the client has a List<Bar> , they must first convert it to an ImmutableList<Bar> before calling foo .缺点:如果客户端有List<Bar> ,他们必须在调用foo之前先将其转换为ImmutableList<Bar> This conversion wastes a small amount of time, and it is forced on clients whether they like it or not.这种转换浪费了少量时间,并且无论他们喜欢与否,它都是强加给客户的。


Note: For the purposes of this question, let's assume that all clients will have Guava's ImmutableList available, for example because the library and client code all belong to the same codebase that already uses ImmutableList elsewhere.注意:出于这个问题的目的,我们假设所有客户端都可以使用 Guava 的ImmutableList ,例如因为库和客户端代码都属于已经在其他地方使用ImmutableList的相同代码库。

As the creator of the foo() API, this is none of your business.作为foo() API 的创建者,这不关你的事。 You take a list and you don't modify it, and that's it.你拿一个清单,你不修改它,就是这样。 Your code, in fact, doesn't care about the list's mutability (it's a concern of the caller): so document your intent and stop there.实际上,您的代码并不关心列表的可变性(这是调用者关心的问题):因此请记录您的意图并停在那里。

If the caller needs to guarantee that the list will not be tampered with, they would create defensive copies not because you don't promise to leave the list unchanged, but because they need that guarantee.如果调用者需要保证列表不会被篡改,他们会创建防御性副本,这不是因为您没有 promise 保持列表不变,而是因为他们需要那个保证。

It's following the same logic that we perform null checks in method implementations: it's needed because our code needs to be robust, not because the caller can send a null argument.它遵循我们在方法实现中执行 null 检查的相同逻辑:需要它是因为我们的代码需要健壮,而不是因为调用者可以发送 null 参数。

In other words, document your method as you intend to implement them, and leave it up to the caller to pick the list implementation.换句话说,按照您打算实现它们的方式记录您的方法,并将其留给调用者来选择列表实现。 The reasons of their choices will vary (ie, it won't always be only whether you'll modify the list).他们选择的原因会有所不同(即,并不总是只有您是否会修改列表)。

Leave it at List .将其留在List

Here are some situations to consider:以下是一些需要考虑的情况:

  • Collections.synchronizedCollection does not modify the client's collection. Collections.synchronizedCollection不会修改客户端的集合。
    • If it forced clients to input an immutable collection, there'd be no use in making it a synchronized collection, since an immutable collection would already be thread safe.如果它强制客户端输入不可变集合,那么将其设为同步集合是没有用的,因为不可变集合已经是线程安全的。
  • Collections.frequency does not modify the client's collection. Collections.frequency不会修改客户端的集合。
    • To check frequency, users would be forced to endure the excess overhead of transferring elements to a new collection.为了检查频率,用户将被迫忍受将元素转移到新集合的额外开销。

These reasons aren't why the JDK doesn't expose an immutable interface.这些原因并不是 JDK 不公开不可变接口的原因。 Those reasons are explained in the documentation .这些原因在文档中进行了解释。 In the case of synchronizedCollection , although it doesn't modify the client's collection, it does return a modifiable view of the client's collection;synchronizedCollection的情况下,虽然它不修改客户端的集合,但它确实返回了客户端集合的可修改视图; some would say this function wouldn't apply here.有人会说这个 function 在这里不适用。 However, frequency and other query functions still hold strong.但是, frequency和其他查询功能仍然很强大。

You shouldn't restrict clients for the purpose of trying to advertise safety and nothing more.您不应该为了宣传安全而限制客户,仅此而已。 There should be more justification, otherwise your attempt to help could be a burden on the client.应该有更多的理由,否则您的帮助可能会成为客户的负担。 In some cases, your goal can be contradictive to what the function/system is achieving, such as with the synchronizedCollection example.在某些情况下,您的目标可能与功能/系统正在实现的目标相矛盾,例如synchronizedCollection示例。

It's good to encourage safety, but having your system force it onto your clients without the system benefiting from it would be abuse of power;鼓励安全是件好事,但是让您的系统将其强加给您的客户,而系统却没有从中受益,那就是滥用权力; that's not your decision to make.这不是你的决定。


ernest_k makes a really good point in his answer , suggesting that you need to analyze what your system should be in charge of, and what the client should be in charge of. ernest_k在他的回答中提出了一个非常好的观点,建议您需要分析您的系统应该负责什么,以及客户应该负责什么。 In this case, it should be up to the client whether the collection is immutable or not, since your system doesn't care about mutability.在这种情况下,集合是否不可变应该由客户端决定,因为您的系统不关心可变性。 As he put it, " it's none of your business ", which I agree with.正如他所说,“这不关你的事”,我同意。

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

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