Arrays.asList() 和 List.of()的区别

set

List.of()不可以使用.set方法改变指定下标的值,Arrays.asList()可以

List<String> listOf = List.of("a", "b", "c");
List<String> arrayAs = Arrays.asList("a", "b", "c");
listOf.set(0, "e");//会报UnsupportedOperationException
arrayAs.set(0, "e");//成功修改
add

都不可以使用.add方法

listOf.add("e");//会报UnsupportedOperationException
arrayAs.add("e");//会报UnsupportedOperationException
remove

都不可使用.remove方法

arrayAs.remove("a");//会报UnsupportedOperationException
listOf.remove("a");//会报UnsupportedOperationException
clear

都不可使用.clear方法

arrayAs.clear();//会报UnsupportedOperationException
listOf.clear();//会报UnsupportedOperationException
初始化包含null

List.of()不可以插入空值,Arrays.asList()可以

List<String> listOf = List.of("a", "b", "c", null, null);//会报NullPointerException
List<String> arrayAs = Arrays.asList("a", "b", "c", null, null);//成功创建
contains

List.of()不可以使用contains方法检验是否存在空值,Arrays.asList()可以

System.out.println(arrayAs.contains(null));
System.out.println(listOf.contains(null));//会报NullPointerException
数组修改对List影响

数组修改对List.of()生成的List无影响,对Arrays.asList()生成的List有影响

String[] arr = new String[]{"a","b","c"};
List<String> listOf = List.of(arr);
List<String> arrayAs = Arrays.asList(arr);
arr[0] = "e";
System.out.println("--------listOf-----------");
listOf.forEach(System.out::println);
System.out.println("--------arrayAs-----------");
arrayAs.forEach(System.out::println);

输出结果为:

--------listOf-----------
a
b
c
--------arrayAs-----------
e
b
c
分析底层代码查看原因
List.of()分析:

下面截取的源码是以List listOf = List.of(arr);为例的,可以看出是将arr中的元素循环遍历出来,循环将值放入新new出的数组中E[] tmp = (E[])new Object[input.length],循环遍历过程中会对值进行判空,若为空则会抛出异常throw new NullPointerException();,这也就是为什么List.of()不能插入空值的原因。再继续看把元素循环放入新数组后赋值给了elements返回,而elements的定义是private final E[] elements;final修饰的,用final修饰的变量是不可变的,直至变量被销毁。

@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);
    }
}
/********************************************************************/
//ImmutableCollections.ListN<>(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;
}
/********************************************************************/
//Objects.requireNonNull(input[i])方法点进去
public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}
/********************************************************************/
//返回值elements是用final修饰的
@Stable
private final E[] elements;

因此使用List.of()创建的数组不可使用.set.add.remove.clear这些修改变量的函数,你会发现这些函数是可以被调用到的,编译也是通过的,但运行起来却是报错的,以.set为例看源码,可以看出来函数里面就做了一个抛异常的操作throw new UnsupportedOperationException();

public E set(int index, E element) {
    throw new UnsupportedOperationException();
}
Arrays.asList()分析:

下面截取的源码是以List arrayAs = Arrays.asList(arr);为例的(以List arrayAs = Arrays.asList("a", "b", "c");为例点进去源码也是一样的),可以看到用此方法生成的集合底层其实是数组,返回集合的底层其实就是传入的数组,只会校验传入的arr是否为空,只要整个数组非空,就不会抛出异常,不会对里面的值进行校验,这就是Arrays.asList()可以插入空值的原因,可以看到返回的a值也是由final修饰的,也是不可变的。

@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}
/********************************************************************/
//new ArrayList<>(a)方法点进去
ArrayList(E[] array) {
    a = Objects.requireNonNull(array);
}
/********************************************************************/
//Objects.requireNonNull(array)方法点进去
public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}
/********************************************************************/
//返回的a是用final修饰的
private final E[] a;

可以使用arr[0] = "e";修改集合的值,这个不难理解,因为用此方法生成的集合底层就是传入的数组,但是为什么可以使用.set修改集合呢,看下面源码,可以看出.set方法里面依旧操作的是数组,so可以成功啦。

@Override
public E set(int index, E element) {
    E oldValue = a[index];
    a[index] = element;
    return oldValue;
}

对于.add.remove.clear这些方法都是不行的,会报错UnsupportedOperationException,毕竟返回值a是被final修饰的private final E[] a;,是不能够被改变的,而这些操作会改变集合的.size属性,so是会报错的。

你可能感兴趣的:(web后端,java,开发语言)