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?
public static void foo(List<Bar> list) {
// ...
}
Pros: Clients can pass in whichever of List<Bar>
or ImmutableList<Bar>
is more convenient for them.
Cons: It is not immediately obvious that the list
parameter will not be mutated. Clients must read documentation and/or code to realize this. Clients may make unnecessary defensive copies anyway.
public static void foo(ImmutableList<Bar> list) {
// ...
}
Pros: Clients have a guarantee that the list
parameter will not be mutated.
Cons: If the client has a List<Bar>
, they must first convert it to an ImmutableList<Bar>
before calling foo
. 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.
The common use case for the immutable methods is a collection that is initialized from known values, and that never changes. Also consider using these methods if your data changes infrequently. For optimal performance, the immutable collections store a data set that never changes.
Immutable objects can be useful in multi-threaded applications. Multiple threads can act on data represented by immutable objects without concern of the data being changed by other threads. Immutable objects are therefore considered more thread-safe than mutable objects.
Mutable is a fancy way of saying that the internal state of the object is changed/mutated. So, the simplest definition is: An object whose internal state can be changed is mutable. On the other hand, immutable doesn't allow any change in the object once it has been created.
The mutable objects can be changed to any value or state without adding a new object. Whereas, the immutable objects can not be changed to its value or state once it is created. In the case of immutable objects, whenever we change the state of the object, a new object will be created.
As the creator of the foo()
API, this is none of your business. 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.
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.
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 (i.e., it won't always be only whether you'll modify the list).
Leave it at List
.
Here are some situations to consider:
Collections.synchronizedCollection
does not modify the client's collection.
Collections.frequency
does not modify the client's collection.
These reasons aren't why the JDK doesn't expose an immutable interface. 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; some would say this function wouldn't apply here. However, frequency
and other query functions still hold strong.
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.
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. 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With