The Java team has done a ton of great work removing barriers to functional programming in Java 8. In particular, the changes to the java.util
Collections do a great job of chaining transformations into very fast streamed operations. Considering how good a job they have done adding first class functions and functional methods on collections, why have they completely failed to provide immutable collections or even immutable collection interfaces?
Without changing any existing code, the Java team could at any time add immutable interfaces that are the same as the mutable ones, minus the setter methods and make the existing interfaces extend from them, like this:
ImmutableIterable
____________/ |
/ |
Iterable ImmutableCollection
| _______/ / \ \___________
| / / \ \
Collection ImmutableList ImmutableSet ImmutableMap ...
\ \ \_________|______________|__________ |
\ \___________|____________ | \ |
\___________ | \ | \ |
List Set Map ...
Sure, operations like List.add()
and Map.put()
currently return a boolean or previous value for the given key to indicate whether the operation succeeded or failed. Immutable collections would have to treat such methods as factories and return a new collection containing the added element - which is incompatible with the current signature. But that could be worked-around by using a different method name like ImmutableList.append()
or .addAt()
and ImmutableMap.putEntry()
. The resulting verbosity would be more than outweighed by the benefits of working with immutable collections, and the type system would prevent errors of calling the wrong method. Over time, the old methods could be deprecated.
Wins of immutable collections:
- Simplicity — reasoning about code is simpler when the underlying data does not change.
- Documentation — if a method takes an immutable collection interface, you know it isn't going to modify that collection. If a method returns an immutable collection, you know you can't modify it.
- Concurrency — immutable collections can be shared safely across threads.
As someone who has tasted languages which assume immutability, it is very hard to go back to the Wild West of rampant mutation. Clojure's collections (sequence abstraction) already have everything that Java 8 collections provide, plus immutability (though maybe using extra memory and time due to synchronized linked-lists instead of streams). Scala has both mutable and immutable collections with a full set of operations, and though those operations are eager, calling .iterator
gives a lazy view (and there are other ways of lazily evaluating them). I don't see how Java can continue to compete without immutable collections.
Can someone point me to the history or discussion about this? Surely it's public somewhere.
const
collectionsCollections.unmodifiable*()
are for. but don't treat these as immutable when they are notImmutableList
in that diagram, people can pass in a mutableList
? No, that's a very bad violation of LSP.