RFR: updated draft API for JEP 269 Convenience Collection Factories

Michael Hixson michael.hixson at gmail.com
Fri Nov 6 13:12:03 UTC 2015

This is in reply to:

+     static <E> List<E> of(E... es) {
+         for (E e : es) {
+             Objects.requireNonNull(e);
+         }
+         // NOTE: this can allow a null element to slip through
+         return Collections.unmodifiableList(Arrays.asList(es));
+     }

Even as a skeletal implementation, this one has to be changed to be
truly immutable, right?  It currently returns a view of the (mutable)
argument array rather than new storage.  Sorry for not providing a
proper test:

  String[] array = { "bar", "baz" };
  List<String> list = of(array);
  System.out.println(list); // [bar, baz]
  array[0] = "foo";
  System.out.println(list); // [foo, baz]

> Regarding the number of fixed-arg overloads, having five List and Set elements
> seemed too few, and even eight key-value pairs for Map seemed too few. I've
> somewhat arbitrarily chosen ten elements and pairs. It seems high enough to
> catch most cases with the fixed-arg overloads, and we still have the varargs as
> an escape hatch.

Has anyone been able to quantify the advantage of having these
overloads as opposed to having the varargs versions only?  Is it a
matter of performance?

I ask because the overloads seem like warts on the APIs (which is a
shame -- List and Set are such important APIs).  I'm imagining a
future where:

1. We add these overloads for performance gains now.
2. But they're all skeletal implementations that aren't that perfomant
anyway.  Efficient versions don't make it into Java SE 9.  People that
care a lot about performance avoid using these ones.
3. A few years later, varargs performance or some other language / VM
/ compiler-level change renders the overloads obsolete.


More information about the core-libs-dev mailing list