0

The arrival of Java 9 brings many new features to Java's Collections API, one of which being collection factory methods.

What are they and how can I implement them properly?

Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • I somewhat agree, I'll try making the question more specific. – Jacob G. Apr 21 '17 at 04:21
  • 3
    I could see this being a great canonical duplicate if the question was just "What are Collection Literals and how do I use them?" – 4castle Apr 21 '17 at 04:23
  • @4castle I just submitted my edit right before you mentioned that, and it seems that we share the same idea. – Jacob G. Apr 21 '17 at 04:24
  • 2
    @JacobG. - I think you are missing Jim's point. Instead of tweaking the question to make it "more acceptable", you should >>put<< the answer into the SO Documentation. – Stephen C Apr 21 '17 at 04:31
  • @StephenC I understand, I'll add it tomorrow when I'm not on my phone. Hopefully I have the privileges to do so. – Jacob G. Apr 21 '17 at 04:42
  • 2
    It will go through the normal review process, but I see no reasons why it should get rejected. – Stephen C Apr 21 '17 at 04:50
  • 1
    @StephenC Well, the reason it should get rejected is that, it is simply not collection literals – Adrian Shum Apr 21 '17 at 08:18
  • 3
    I suggest renaming the question to **"Java 9: What are Collection factory methods?"** according to JEP 269. Collection literals were proposed in JEP 186 and were rejected. – ZhekaKozlov Apr 21 '17 at 09:34
  • @AdrianShum - That's wrong. It should be accepted and then the minor problems should be fixed. That's the way we do it in the Java Documentation. – Stephen C Apr 21 '17 at 10:04
  • @ZhekaKozlov I agree, I'll change it right now! – Jacob G. Apr 21 '17 at 15:34
  • I've submitted documentation for collection factory methods. – Jacob G. Apr 21 '17 at 19:04

1 Answers1

10

Note 1: To prevent the use of raw-types, I have opted to provide a generic type for each class that I mention below by using E, representing an element of a Collection<E>.

Note 2: This answer is subject to change; please edit this post if a typo has occurred.

What are collection factory methods?

A collection factory method in Java is a static method that provides a simple way of initializing an immutable Collection<E>.

Being immutable, no elements can be added to, removed from, or modified inside the Collection<E> after it is initialized.

With Java 9, collection factory methods are provided for the following interfaces: List<E>, Set<E>, and Map<K, V>

What do they improve?

Up until Java 9, there has been no simple, universal method to initialize a Collection<E> with initial elements/key-value entries. Previously, developers were required to initialize them as follows (assuming the generic types E, K, and V have been replaced with Integer):

  • List<Integer>
    • The following method is arguably the simplest to initialize a List<Integer> with initial elements, however the result is simply a view of a List<Integer>; we are unable to add to or remove from this List<Integer>, but we are still able to modify existing elements by using List#set.
      • List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    • If we wanted our List<Integer> to be entirely mutable, then we would have to pass it to the constructor of an ArrayList<Integer>, for example:
      • List<Integer> mutableList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
  • Set<Integer>
    • A Set<Integer> required more code to initialize with initial elements than a List<Integer> does (seeing as a List<Integer> is required to initialize a Set<Integer> with initial elements), which can be seen below.
      • Set<Integer> mutableSet = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
  • Map<Integer, Integer>
    • A Map<Integer, Integer> is arguably the most complicated to initialize with initial key-value entries; however, there are multiple ways to go about it.
      • One method was to first initialize an empty Map<Integer, Integer> and simply call Map#put to add key-value entries.
      • Another method was to use an anonymous class with two curly braces, which would still require Map#put to be called.

Why should I use them?

I argue that collection factory methods provide the developer with a concise method of initializing a List<E>, Set<E>, or Map<K, V> with initial elements/key-value entries, which can be seen by the examples below.

What is the proper syntax to use?

For simplicity, these examples will replace the generic types E, K, and V with Integer.

  • List<Integer>
    • List<Integer> list = List.of();
      • Initializes an empty, immutable List<Integer>.
    • List<Integer> list = List.of(1);
      • Initializes an immutable List<Integer> with one element.
    • List<Integer> list = List.of(1, 2);
      • Initializes an immutable List<Integer> with two elements.
    • List<Integer> list = List.of(1, 2, 3, 4, 5, ...);
      • Initializes an immutable List<Integer> with a variable amount of elements.
  • Set<Integer>
    • Set<Integer> set = Set.of();
      • Initializes an empty, immutable Set<Integer>.
    • Set<Integer> set = Set.of(1);
      • Initializes an immutable Set<Integer> with one element.
    • Set<Integer> set = Set.of(1, 2);
      • Initializes an immutable Set<Integer> with two elements.
    • Set<Integer> set = Set.of(1, 2, 3, 4, 5, ...);
      • Initializes an immutable Set<Integer> with a variable amount of elements.
  • Map<Integer, Integer>
    • Map<Integer, Integer> map = Map.of();
      • Initializes an empty, immutable Map<Integer, Integer>.
    • Map<Integer, Integer> map = Map.of(1, 2);
      • Initializes an immutable Map<Integer, Integer> with one key-value entry.
      • Note that the key is 1 and the value is 2.
    • Map<Integer, Integer> map = Map.of(1, 2, 3, 4);
      • Initializes an immutable Map<Integer, Integer> with two key-value entries.
      • Note that the keys are 1 and 3 and the values are 2 and 4.
    • Map<Integer, Integer> map = Map.ofEntries(Map.entry(1, 2), Map.entry(3, 4), ...);
      • Initializes an immutable Map<Integer, Integer> with a variable amount of key-value entries.

As you can see, this new method of initialization requires less code than its predecessors.

Can I use collection factory methods to create mutable objects?

The Collection<E> created by collection factory methods are inherently immutable, however we are able to pass them to a constructor of an implementation of the Collection<E> to produce a mutable version:

  • List<Integer>
    • List<Integer> mutableList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
  • Set<Integer>
    • Set<Integer> mutableSet = new HashSet<>(Set.of(1, 2, 3, 4, 5));
  • Map<Integer, Integer>
    • Map<Integer, Integer> mutableMap = new HashMap<>(Map.of(1, 2, 3, 4));
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • 5
    `Map` IS in Collection API. Collection is more than things implementing `Collection` – Adrian Shum Apr 21 '17 at 08:03
  • 4
    and, I doubt this can be called collection *literal*. They are just collection factory methods, which allow ease of creating collections **without** collection literals. – Adrian Shum Apr 21 '17 at 08:07
  • 2
    @Jacob I suggest renaming the question to **"Java 9: What are Collection factory methods?"** according to JEP 269. Collection literals were proposed in JEP 186 and were rejected. – ZhekaKozlov Apr 21 '17 at 09:31
  • 1
    What is the point of saying “(non)empty”? Are you trying to say that the collections are either, empty or not empty? That’s a not a real statement. – Holger Apr 21 '17 at 11:19
  • Thank you for your suggestions! I have edited the answer to ameliorate the issues. – Jacob G. Apr 21 '17 at 15:39
  • 1
    The section "How are they implemented" isn't a concern of any users of the API. All the classes mentioned are private, and they are subject to change in future releases. – Stuart Marks Apr 21 '17 at 16:41
  • @StuartMarks I only listed it because, like me, some developers might be interested in its implementation. It doesn't hurt to have it, and I'll gladly edit it if a change is made. – Jacob G. Apr 21 '17 at 16:43
  • @OusmaneMahyDiaw It can be closed if needed, I've already submitted documentation for it :) – Jacob G. Apr 21 '17 at 19:03
  • So now we can do `Set mutableSet = new HashSet<>(Set.of(1, 2, 3, 4, 5));` and saved 7 characters, what an improvement /s. Also what use is unmodifiable map? Lazy developers not needing to create a proper Class or better Enum / EnumSet? This will just cause `UnsupportedOperationException` to enter top 10 Java exceptions in production code. – Terran Dec 28 '17 at 13:26
  • 1
    The internal implementations of these classes have changed in Java 11, so the early section on implementation details is now obsolete. – Stuart Marks Mar 29 '18 at 16:23
  • @StuartMarks Thanks for letting me know; I'll remove it! – Jacob G. Mar 29 '18 at 16:44