1. 概述
在Java编程中,当我们处理集合时,List
是一个常用的类型。
我们都知道,我们可以很容易地使用一行代码来初始化 List
。例如,当我们要用单个元素初始化一个 List
时,可以使用 Arrays.asList()
方法或 Collections.singletonList()
方法。
在这篇教程中,我们将讨论这两种方法的区别。然后,为了简化,我们将使用单元测试断言来验证某些操作是否按预期执行。
2. Arrays.asList()
方法
首先,Arrays.asList()
方法返回的是一个固定大小的列表。
任何结构更改(如添加新元素或删除元素)都会抛出 UnsupportedOperationException
。现在,让我们通过测试来验证这一点:
List<String> arraysAsList = Arrays.asList("ONE");
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(
() -> arraysAsList.add("TWO")
);
如果运行测试,它会通过。在上面的代码中,我们使用了 Assertj 的异常断言 来验证当我们尝试向列表中添加新元素时是否会抛出 UnsupportedOperationException
。
尽管不能对列表调用 add()
或 remove()
操作,但我们可以使用 set()
方法修改列表中的元素:
arraysAsList.set(0, "A brand new string");
assertThat(arraysAsList.get(0)).isEqualTo("A brand new string");
这次,我们用一个新的 String
对象设置列表中的元素。如果执行测试,它也会通过。
最后,让我们谈谈 Arrays.asList()
方法中的数组与返回的列表之间的关系。
如方法名所示,这个方法使数组充当一个 List
。让我们理解一下这意味着什么。
Arrays.asList()
方法返回一个 List
对象,它由给定的数组支持。也就是说,方法不会将数组中的元素复制到新的 List
对象中。相反,它提供了对给定数组的 List
视图。因此,我们在数组上所做的任何更改都会反映在返回的列表中。同样,对列表所做的更改也会反映在数组上:
String[] theArray = new String[] { "ONE", "TWO" };
List<String> theList = Arrays.asList(theArray);
//changing the list, the array is changed too
theList.set(0, "ONE [changed in list]");
assertThat(theArray[0]).isEqualTo("ONE [changed in list]");
//changing the array, the list is changed too
theArray[1] = "TWO [changed in array]";
assertThat(theList.get(1)).isEqualTo("TWO [changed in array]");
测试通过。所以对于数组和返回的列表,如果我们对一边进行了更改,另一边也会相应改变。
3. Collections.singletonList()
方法
首先,singletonList()
方法返回的列表只有一个元素。与 Arrays.asList()
不同,singletonList()
返回的是一个不可变列表。
换句话说,返回的列表不允许进行结构和非结构更改。一个测试可以快速说明这一点:
List<String> singletonList = Collections.singletonList("ONE");
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(
() -> singletonList.add("TWO")
);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(
() -> singletonList.set(0, "A brand new string")
);
如果运行测试,它会通过。因此,无论我们是向列表中添加元素还是更改列表中的元素,它都会抛出 UnsupportedOperationException
。
值得一提的是,如果我们查看返回列表类的源代码,与其他 List
实现不同,返回列表中的单个元素并不存储在数组或其他复杂数据结构中。相反,列表直接持有元素对象:
private static class SingletonList<E> extends AbstractList<E> implements RandomAccess, Serializable {
...
private final E element;
SingletonList(E obj) {element = obj;}
...
}
因此,它占用的内存更少。
4. 简短总结
最后,让我们以表格形式总结 Arrays.asList()
方法和 Collections.singletonList()
方法的特点,以便更好地了解:
Arrays.asList()
Collections.singletonList()
结构更改
不允许
不允许
非结构更改
允许
不允许
数据结构
由数组支持
直接持有元素
5. 结论
在这篇简短的文章中,我们讨论了 Arrays.asList()
方法和 Collections.singletonList()
方法。
当我们想用单个元素初始化一个固定大小的列表时,可以考虑使用 Collections.singletonList()
方法。然而,如果需要修改返回列表中的元素,可以选择 Arrays.asList()
方法。
如往常一样,示例的完整源代码可在GitHub 上找到。