Specific Collection type returned by Convenience F

2019-01-26 17:52发布

问题:

In Java 9 we have convenience factory methods to create and instantiate immutable List, Set and Map.

However, it is unclear about the specific type of the returned object.

For ex:

List list = List.of("item1", "item2", "item3");

In this case which type of list is actually returned? Is it an ArrayList or a LinkedList or some other type of List?

The API documentation just mentions this line, without explicitly mentioning that its a LinkedList:

The order of elements in the list is the same as the order of the provided arguments, or of the elements in the provided array.

回答1:

The class returned by List.of is one of the package-private static classes and therefore not part of the public API:

package java.util;
...

class ImmutableCollections {
    ...

    static final class List0<E> extends AbstractImmutableList<E> {
        ...
    }

    static final class List1<E> extends AbstractImmutableList<E> {
        ...
    }

    static final class List2<E> extends AbstractImmutableList<E> {
        ...
    }

    static final class ListN<E> extends AbstractImmutableList<E> {
        ...
    }
}

So this is not an ArrayList (neither a LinkedList). The only things you need to know is that it is immutable and satisfies the List interface contract.



回答2:

However, it is unclear about the specific type of the returned object.

And that is all you need to know! The whole point is: these methods do return some List<Whatever> on purpose. The thing that you get back is guaranteed to fulfill the public contract denoted by the List interface. It is a list of the things given to that method, in the same order as those things were written down.

You absolutely should avoid writing any code that needs to know more about the lists returned by these methods! That is an implementation detail which should not matter to client code invoking these methods!

In that sense: your focus should be much more on the client side - for example by avoiding that raw type you are using in your example (using List without a specific generic type).



回答3:

Though the question seems to have been answered by @ZhekaKozlov and @GhostCat both in terms of what the return type would be(ImmutableCollections.List) and how it has been created package private and is not a public API. Also adding to the facts that the implementation of these factory methods guarantees to fulfill the public contract denoted by the List interface.


To further provide a gist of the implementation of the ImmutableCollections then Set, Map and List a step further in it. I would add a sample representation for a List which is quite similar for Map and Set.


The ImmutableCollections currently implements these factory methods on the interface List using:

abstract static class AbstractImmutableList<E>

which extends the AbstractList class and throws an UnsupportedOperationException for all the possible operations overriding their implementation. Meaning no more operations allowed on the collection, making them equivalent to Java Immutable Collections.

Furthermore, this is extended by a class

static final class ListN<E> extends AbstractImmutableList<E>

with a constructor to evaluate certain checks for the input and its elements being NonNull to return the object consisting of an E[] elements(array of elements of type E) and overrides certain implementations as .get(int idx), .contains(Object o) based out of these elements.


The way it goes on for Map and Set is similar, just that the validations on top of the elements or a pair of key and value are ensured there. Such that you can't create these(throws IllegalArgumentException and NullPointer exceptions respectively) :

Set<String> set2 = Set.of("a", "b", "a");
Map<String,String> map = Map.of("key1","value1","key1","value1");

Set<String> set2 = Set.of("a", null);
Map<String,String> map = Map.of("key1",null);


回答4:

Actually the same idea is in Collectors.toList for example - you get a List back and the documentation specifically says : There are no guarantees on the type, mutability, serializability, or thread-safety of the List returned. At the moment it is an ArrayList returned, but obviously this can change at any point in time.

I wonder if the same should be done here - to explicitly mention that the type is a List and nothing more. This let's a lot of ground for future implementations to decide what type to return that would fit best - speed, space, etc.



回答5:

List.of returns a List of special type like Collections.UnmodifiableList. It is neither an ArrayList nor LinkedList. It will throw an exception when you will try to modify it.