Hi Dan, thanks for the feedback.
On 7/17/14 10:40 AM, Dan Smith wrote:
The motivation section ought to more directly survey what we have now:
- Collections.emptyList/emptySet/emptyMap
- Collections.singletonList/singleton/singletonMap
- Arrays.asList
- EnumSet.of (varargs, plus some overloads)
- Stream.empty and Stream.of (singleton plus varargs)
- Constructors that, by convention, always have a variant that constructs an
empty collection and another to copy the contents of an existing collection
This helps to clarify that there are multiple goals:
- Provide some default methods in List/Set/Map for easier access to existing
behavior (following the pattern of EnumSet)
- Add new functionality to create immutable Sets/Maps for 2 <= n <= small
number.
- (Maybe?) varargs methods to create immutable Sets/Maps or arbitrary size.
- Provide an array-less implementation of immutable Lists for 2 <= n <= small
number.
WAT, you mean not everybody is a collections expert? :-)
Sure, I could add some background here. The relationship with the
Collections.empty* and Collections.singleton* methods is especially interesting.
They're not very discoverable; they're somewhat verbose, and the naming is odd.
(Where is singletonSet? oh.) The implementation returned by Arrays.asList is
also incredibly useful but is something of a strange beast compared to other
collections.
"If a mutable collection is desired, the contents of an immutable collection can easily be
copied into a collection type of the caller's choice." ... "If there are sufficient use
cases to support convenient creation of mutable collections, factory methods for particular mutable
collection classes could be added."
Following the existing convention, it might make more sense to make these
constructors:
ArrayList()
ArrayList(Collection<? extends E>)
ArrayList(E...) // this is new
Note there is also ArrayList(int initialCapacity).
This brings in the old constructor-vs-factory-method discussion. A constructor
is reasonable since we have no intention of returning an instance of a subclass,
which would be a point in favor of a static factory. But I'm concerned about
adding the varargs constructor next to existing constructors. Many of the
collections have additional constructors besides the ones provided by
convention. There may not be any actual ambiguity, but surprising behaviors
would result. For example, in
List<Integer> list1 = new ArrayList<>(1, 2);
List<Integer> list2 = new ArrayList<>(3);
list1 would be [1, 2] as expected but list2 would be an empty list with an
initial capacity of 3.
HashSet has a similar issues with the constructor
HashSet(int initialCapacity, float loadFactor)
"Converting a mutable collection into an immutable one is more difficult."
In principle, if you've got a varargs List creation method, there's nothing to
stop you from overloading it with an Collection/Iterable/Stream version. Same
functionality, although this might encourage users to think that larger
collections will behave properly. (You could pass in a large array to the
varargs method, but presumably most users will be passing in small varargs
lists.)
What I meant by "...is more difficult" is that, prior to any of these proposals,
creating an immutable collection when given a mutable one is more difficult. (Or
at least, it's a pain.) You could copy the collection into a new collection, and
then wrap it in an unmodifiable wrapper. Or you could import a third party
library with actual immutable collections. Or you could write your own.
I guess I should clarify this too.
If we were to add a family of immutable collections to the JDK, as has popped up
a couple times on this thread, its constructors or factories should clearly be
able to consume other collections, streams, etc.
I was curious about other collections that might benefit.
- It turns out Queue and Deque are pretty useless as immutable data structures.
- SortedSet and SortedMap could be useful.
- Stream could probably be made consistent with the overloading scheme you
settle on; EnumSet, too, if it's different.
- There might be some use cases for Iterator; likely doesn't carry its weight,
though.
Yes, interesting. Most collection implementations have special features that
apply to mutability. The Sorted (or maybe Navigable) variations of Set or Map
could be useful though.
s'marks
—Dan
On Jul 16, 2014, at 6:46 PM, Stuart Marks <stuart.ma...@oracle.com> wrote:
Hi all,
Please review this draft JEP for Convenience Factory Methods for Collections:
https://bugs.openjdk.java.net/browse/JDK-8048330
Brief background: several times over the years there have been proposals to add
"collection literals" to the language. The most recent round of this was in
regard to JEP 186, a research JEP to explore this topic. That effort was concluded by
Brian Goetz, as summarized in this email:
http://mail.openjdk.java.net/pipermail/lambda-dev/2014-March/011938.html
Essentially, the idea of adding collection literals to the language was set
aside in favor of adding some library APIs, not entirely unlike collection
literals, that make it more convenient to create collections. That's what this
proposal is.
Share and enjoy,
s'marks