Oracle 公司引入一些方便使用的工厂方法,用于创建不可变集合 List,Set,Map 和 Map.Entry 对象。这些高效实用的方法可用来创建空或者非空集合对象。
在 Java SE 8 和更早版本中,我们常用类似 unmodifiableXXX 的集合类方法创建不可变集合对象。举个例子,比如我们想创建一个不可变的 List 对象,可能使用到Collections.unmodifiableList 方法。
然而,这些 Collections.unmodifiableXXX 方法显得非常冗长乏味。为了克服这些缺陷,Oracle 公司给 List、Set 和 Map 接口分别添加了两个更加实用的方法。
List 和 Set 接口使用 of() 方法创建一个空或者非空的不可变 List 或 Set 对象,如:
空 List 示例
List immutableList = List.of();
非空 List 示例
List immutableList = List.of(“one”,“two”,“three”);
Map 分别有两个方法用于创建不可变 Map 对象和不可变 Map.Entry 对象:of() 和 ofEntries()。
空 Map 示例
jshell> Map emptyImmutableMap = Map.of()
emptyImmutableMap ==> {}
非空 Map 示例
jshell> Map nonemptyImmutableMap = Map.of(1, “one”, 2, “two”, 3, “three”)
nonemptyImmutableMap ==> {2=two, 3=three, 1=one}
/**
* Returns an unmodifiable list containing zero elements.
*
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
*
* @param <E> the {@code List}'s element type
* @return an empty {@code List}
*
* @since 9
*/
static <E> List<E> of() {
return ImmutableCollections.emptyList();
}
创建不可变的空集合,调用了ImmutableCollections.emptyList方法。
入参是E…时:
/**
* Returns an unmodifiable list containing an arbitrary number of elements.
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
*
* @apiNote
* This method also accepts a single array as an argument. The element type of
* the resulting list will be the component type of the array, and the size of
* the list will be equal to the length of the array. To create a list with
* a single element that is an array, do the following:
*
* <pre>{@code
* String[] array = ... ;
* List<String[]> list = List.<String[]>of(array);
* }</pre>
*
* This will cause the {@link List#of(Object) List.of(E)} method
* to be invoked instead.
*
* @param <E> the {@code List}'s element type
* @param elements the elements to be contained in the list
* @return a {@code List} containing the specified elements
* @throws NullPointerException if an element is {@code null} or if the array is {@code null}
*
* @since 9
*/
@SafeVarargs
@SuppressWarnings("varargs")
static <E> List<E> of(E... elements) {
switch (elements.length) { // implicit null check of elements
case 0:
return ImmutableCollections.emptyList();
case 1:
return new ImmutableCollections.List12<>(elements[0]);
case 2:
return new ImmutableCollections.List12<>(elements[0], elements[1]);
default:
return new ImmutableCollections.ListN<>(elements);
}
}
static List of(E… elements)方法根据传入参数的长度调用ImmutableCollections相对应的方法。
List12(E e0) {
this.e0 = Objects.requireNonNull(e0);
this.e1 = null;
}
List12(E e0, E e1) {
this.e0 = Objects.requireNonNull(e0);
this.e1 = Objects.requireNonNull(e1);
}
当传入参数的元素为一个或两个元素时,用了一个重载方法。接下来看ListN<>
static final class ListN<E> extends AbstractImmutableList<E>
implements Serializable {
static final List<?> EMPTY_LIST = new ListN<>();
@Stable
private final E[] elements;
@SafeVarargs
ListN(E... input) {
// copy and check manually to avoid TOCTOU
@SuppressWarnings("unchecked")
E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
for (int i = 0; i < input.length; i++) {
tmp[i] = Objects.requireNonNull(input[i]);
}
elements = tmp;
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public int size() {
return elements.length;
}
@Override
public E get(int index) {
return elements[index];
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("not serial proxy");
}
private Object writeReplace() {
return new CollSer(CollSer.IMM_LIST, elements);
}
}
ListN<>方法会先生成一个跟入参长度相同的元素数组,for循环将入参的元素赋值给新建的元素数组,并且对每一个元素判断是否为NULL。如果为NULL则抛出空指针异常。
/**
* Checks that the specified object reference is not {@code null}. This
* method is designed primarily for doing parameter validation in methods
* and constructors, as demonstrated below:
* <blockquote><pre>
* public Foo(Bar bar) {
* this.bar = Objects.requireNonNull(bar);
* }
* </pre></blockquote>
*
* @param obj the object reference to check for nullity
* @param <T> the type of the reference
* @return {@code obj} if not {@code null}
* @throws NullPointerException if {@code obj} is {@code null}
*/
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
如果对不可变集合中添加元素会怎么样???
Exception in thread "main" java.lang.UnsupportedOperationException
at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:71)
at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:75)
at com.fengyue.java11.java11.main(java11.java:10)
会抛出 java.lang.UnsupportedOperationException异常。